texnodes.c /size: 256 Kb    last modification: 2024-01-16 10:22
1/*
2    See license.txt in the root of this project.
3*/
4
5# include "luametatex.h"
6
7/*tex TODO: update field specifications for added node entries */
8
9/*tex
10
11    This module started out using DEBUG to trigger checking invalid node usage, something that is
12    needed because users can mess up nodes in \LUA. At some point that code was always enabled so
13    it is now always on but still can be recognized as additional code. And as the performance hit
14    is close to zero so disabling makes no sense, not even to make it configureable. There is a
15    little more memory used but that is neglectable compared to other memory usage. Only on
16    massive freeing we can gain.
17
18*/
19
20node_memory_state_info lmt_node_memory_state = {
21    .nodes       = NULL,
22    .nodesizes   = NULL,
23    .free_chain  = { null },
24    .nodes_data  = {
25        .minimum   = min_node_size,
26        .maximum   = max_node_size,
27        .size      = siz_node_size,
28        .step      = stp_node_size,
29        .allocated = 0,
30        .itemsize  = sizeof(memoryword) + sizeof(char),
31        .top       = 0, // beware, node pointers are just offsets below top
32        .ptr       = 0, // total size in use
33        .initial   = 0,
34        .offset    = 0,
35    },
36    .extra_data  = {
37        .minimum   = memory_data_unset,
38        .maximum   = memory_data_unset,
39        .size      = memory_data_unset,
40        .step      = memory_data_unset,
41        .allocated = 0,
42        .itemsize  = 1,
43        .top       = 0,
44        .ptr       = 0,
45        .initial   = memory_data_unset,
46        .offset    = 0,
47    },
48    .reserved                      = 0,
49    .padding                       = 0,
50    .node_properties_id            = 0,
51    .lua_properties_level          = 0,
52    .attribute_cache               = 0,
53    .max_used_attribute            = 1,
54    .node_properties_table_size    = 0,
55};
56
57/*tex Defined below. */
58
59static void     tex_aux_check_node      (halfword node);
60static halfword tex_aux_allocated_node  (int size);
61
62/*tex
63
64    The following definitions are used for keys at the \LUA\ end and provide an efficient way to
65    share hashed strings. For a long time we had this:
66
67    static value_info lmt_node_fields_accent  [10];
68
69    node_info lmt_node_data[] = {
70        { .id = hlist_node, .size = box_node_size, .subtypes = NULL, .fields = lmt_node_fields_list, .name = NULL, .lua = 0, .visible = 1 },
71        ....
72    } ;
73
74    etc but eventually we went a bit more dynamic because after all some helpers showeed up. This
75    brings many node properties together. Not all nodes are visible for users. Most of the
76    properties can be provided as lists.
77
78    not all math noad fields are mentioned here yet ... some are still experimental
79
80*/
81
82void lmt_nodelib_initialize(void) {
83
84    /*tes The subtypes of nodes. */
85
86    value_info
87        *subtypes_dir, *subtypes_par, *subtypes_glue, *subtypes_boundary, *subtypes_penalty, *subtypes_kern,
88        *subtypes_rule, *subtypes_glyph , *subtypes_disc, *subtypes_list, *subtypes_adjust, *subtypes_mark,
89        *subtypes_math, *subtypes_noad, *subtypes_radical, *subtypes_choice, *subtypes_accent, *subtypes_fence, *subtypes_split,
90        *subtypes_attribute;
91
92    value_info
93        *lmt_node_fields_accent, *lmt_node_fields_adjust, *lmt_node_fields_attribute,
94        *lmt_node_fields_boundary, *lmt_node_fields_choice, *lmt_node_fields_delimiter, *lmt_node_fields_dir,
95        *lmt_node_fields_disc, *lmt_node_fields_fence, *lmt_node_fields_fraction, *lmt_node_fields_glue,
96        *lmt_node_fields_glue_spec, *lmt_node_fields_glyph, *lmt_node_fields_insert, *lmt_node_fields_split,
97        *lmt_node_fields_kern, *lmt_node_fields_list, *lmt_node_fields_par, *lmt_node_fields_mark, *lmt_node_fields_math,
98        *lmt_node_fields_math_char, *lmt_node_fields_math_text_char, *lmt_node_fields_noad, *lmt_node_fields_penalty,
99        *lmt_node_fields_radical, *lmt_node_fields_rule, *lmt_node_fields_style, *lmt_node_fields_parameter,
100        *lmt_node_fields_sub_box, *lmt_node_fields_sub_mlist, *lmt_node_fields_unset, *lmt_node_fields_whatsit;
101
102    subtypes_dir = lmt_aux_allocate_value_info(cancel_dir_subtype);
103
104    set_value_entry_key(subtypes_dir, normal_dir_subtype, normal)
105    set_value_entry_key(subtypes_dir, cancel_dir_subtype, cancel)
106
107    subtypes_split = lmt_aux_allocate_value_info(insert_split_subtype);
108
109    set_value_entry_key(subtypes_split, normal_split_subtype, normal)
110    set_value_entry_key(subtypes_split, insert_split_subtype, insert)
111
112    subtypes_par = lmt_aux_allocate_value_info(math_par_subtype);
113
114    set_value_entry_key(subtypes_par, vmode_par_par_subtype, vmodepar)
115    set_value_entry_key(subtypes_par, local_box_par_subtype, localbox)
116    set_value_entry_key(subtypes_par, hmode_par_par_subtype, hmodepar)
117    set_value_entry_key(subtypes_par, parameter_par_subtype, parameter)
118    set_value_entry_key(subtypes_par, math_par_subtype,      math)
119
120    subtypes_glue = lmt_aux_allocate_value_info(u_leaders);
121
122    set_value_entry_key(subtypes_glue, user_skip_glue,                userskip)
123    set_value_entry_key(subtypes_glue, line_skip_glue,                lineskip)
124    set_value_entry_key(subtypes_glue, baseline_skip_glue,            baselineskip)
125    set_value_entry_key(subtypes_glue, par_skip_glue,                 parskip)
126    set_value_entry_key(subtypes_glue, above_display_skip_glue,       abovedisplayskip)
127    set_value_entry_key(subtypes_glue, below_display_skip_glue,       belowdisplayskip)
128    set_value_entry_key(subtypes_glue, above_display_short_skip_glue, abovedisplayshortskip)
129    set_value_entry_key(subtypes_glue, below_display_short_skip_glue, belowdisplayshortskip)
130    set_value_entry_key(subtypes_glue, left_skip_glue,                leftskip)
131    set_value_entry_key(subtypes_glue, right_skip_glue,               rightskip)
132    set_value_entry_key(subtypes_glue, top_skip_glue,                 topskip)
133    set_value_entry_key(subtypes_glue, split_top_skip_glue,           splittopskip)
134    set_value_entry_key(subtypes_glue, tab_skip_glue,                 tabskip)
135    set_value_entry_key(subtypes_glue, space_skip_glue,               spaceskip)
136    set_value_entry_key(subtypes_glue, xspace_skip_glue,              xspaceskip)
137    set_value_entry_key(subtypes_glue, zero_space_skip_glue,          zerospaceskip)
138    set_value_entry_key(subtypes_glue, par_fill_left_skip_glue,       parfillleftskip)
139    set_value_entry_key(subtypes_glue, par_fill_right_skip_glue,      parfillskip)
140    set_value_entry_key(subtypes_glue, par_init_left_skip_glue,       parinitleftskip)
141    set_value_entry_key(subtypes_glue, par_init_right_skip_glue,      parinitrightskip)
142    set_value_entry_key(subtypes_glue, indent_skip_glue,              indentskip)
143    set_value_entry_key(subtypes_glue, left_hang_skip_glue,           lefthangskip)
144    set_value_entry_key(subtypes_glue, right_hang_skip_glue,          righthangskip)
145    set_value_entry_key(subtypes_glue, correction_skip_glue,          correctionskip)
146    set_value_entry_key(subtypes_glue, inter_math_skip_glue,          intermathskip)
147    set_value_entry_key(subtypes_glue, ignored_glue,                  ignored)
148    set_value_entry_key(subtypes_glue, page_glue,                     page)
149    set_value_entry_key(subtypes_glue, math_skip_glue,                mathskip)
150    set_value_entry_key(subtypes_glue, thin_mu_skip_glue,             thinmuskip)
151    set_value_entry_key(subtypes_glue, med_mu_skip_glue,              medmuskip)
152    set_value_entry_key(subtypes_glue, thick_mu_skip_glue,            thickmuskip)
153    set_value_entry_key(subtypes_glue, conditional_math_glue,         conditionalmathskip)
154    set_value_entry_key(subtypes_glue, rulebased_math_glue,           rulebasedmathskip)
155    set_value_entry_key(subtypes_glue, mu_glue,                       muglue)
156    set_value_entry_key(subtypes_glue, a_leaders,                     leaders)
157    set_value_entry_key(subtypes_glue, c_leaders,                     cleaders)
158    set_value_entry_key(subtypes_glue, x_leaders,                     xleaders)
159    set_value_entry_key(subtypes_glue, g_leaders,                     gleaders)
160    set_value_entry_key(subtypes_glue, u_leaders,                     uleaders)
161
162    subtypes_boundary = lmt_aux_allocate_value_info(math_boundary);
163
164    set_value_entry_key(subtypes_boundary, cancel_boundary,     cancel)
165    set_value_entry_key(subtypes_boundary, user_boundary,       user)
166    set_value_entry_key(subtypes_boundary, protrusion_boundary, protrusion)
167    set_value_entry_key(subtypes_boundary, word_boundary,       word)
168    set_value_entry_key(subtypes_boundary, page_boundary,       page)
169    set_value_entry_key(subtypes_boundary, math_boundary,       math)
170 /* set_value_entry_key(subtypes_boundary, par_boundary,        par) */
171
172    subtypes_penalty = lmt_aux_allocate_value_info(equation_number_penalty_subtype);
173
174    set_value_entry_key(subtypes_penalty, user_penalty_subtype,            userpenalty)
175    set_value_entry_key(subtypes_penalty, linebreak_penalty_subtype,       linebreakpenalty)
176    set_value_entry_key(subtypes_penalty, line_penalty_subtype,            linepenalty)
177    set_value_entry_key(subtypes_penalty, word_penalty_subtype,            wordpenalty)
178    set_value_entry_key(subtypes_penalty, final_penalty_subtype,           finalpenalty)
179    set_value_entry_key(subtypes_penalty, orphan_penalty_subtype,          orphanpenalty)
180    set_value_entry_key(subtypes_penalty, single_line_penalty_subtype,     singlelinepenalty)
181    set_value_entry_key(subtypes_penalty, math_pre_penalty_subtype,        mathprepenalty)
182    set_value_entry_key(subtypes_penalty, math_post_penalty_subtype,       mathpostpenalty)
183    set_value_entry_key(subtypes_penalty, before_display_penalty_subtype,  beforedisplaypenalty)
184    set_value_entry_key(subtypes_penalty, after_display_penalty_subtype,   afterdisplaypenalty)
185    set_value_entry_key(subtypes_penalty, equation_number_penalty_subtype, equationnumberpenalty)
186
187    subtypes_kern = lmt_aux_allocate_value_info(vertical_math_kern_subtype);
188
189    set_value_entry_key(subtypes_kern, font_kern_subtype,            fontkern)
190    set_value_entry_key(subtypes_kern, explicit_kern_subtype,        userkern)
191    set_value_entry_key(subtypes_kern, accent_kern_subtype,          accentkern)
192    set_value_entry_key(subtypes_kern, italic_kern_subtype,          italiccorrection)
193    set_value_entry_key(subtypes_kern, left_correction_kern_subtype, leftcorrectionkern)
194    set_value_entry_key(subtypes_kern, right_correction_kern_subtype,rightcorrectionkern)
195    set_value_entry_key(subtypes_kern, space_font_kern_subtype,      spacefontkern)
196    set_value_entry_key(subtypes_kern, left_margin_kern_subtype,     leftmarginkern)
197    set_value_entry_key(subtypes_kern, right_margin_kern_subtype,    rightmarginkern)
198    set_value_entry_key(subtypes_kern, explicit_math_kern_subtype,   mathkern)
199    set_value_entry_key(subtypes_kern, math_shape_kern_subtype,      mathshapekern)
200    set_value_entry_key(subtypes_kern, horizontal_math_kern_subtype, horizontalmathkern)
201    set_value_entry_key(subtypes_kern, vertical_math_kern_subtype,   verticalmathkern)
202
203    subtypes_rule = lmt_aux_allocate_value_info(image_rule_subtype);
204
205    set_value_entry_key(subtypes_rule, normal_rule_subtype,        normal)
206    set_value_entry_key(subtypes_rule, empty_rule_subtype,         empty)
207    set_value_entry_key(subtypes_rule, strut_rule_subtype,         strut)
208    set_value_entry_key(subtypes_rule, outline_rule_subtype,       outline)
209    set_value_entry_key(subtypes_rule, user_rule_subtype,          user)
210    set_value_entry_key(subtypes_rule, math_over_rule_subtype,     over)
211    set_value_entry_key(subtypes_rule, math_under_rule_subtype,    under)
212    set_value_entry_key(subtypes_rule, math_fraction_rule_subtype, fraction)
213    set_value_entry_key(subtypes_rule, math_radical_rule_subtype,  radical)
214    set_value_entry_key(subtypes_rule, box_rule_subtype,           box)
215    set_value_entry_key(subtypes_rule, image_rule_subtype,         image)
216    set_value_entry_key(subtypes_rule, virtual_rule_subtype,       virtual)
217
218    subtypes_glyph = lmt_aux_allocate_value_info(glyph_math_accent_subtype);
219
220    set_value_entry_key(subtypes_glyph, glyph_unset_subtype,            unset)
221    set_value_entry_key(subtypes_glyph, glyph_character_subtype,        character)
222    set_value_entry_key(subtypes_glyph, glyph_ligature_subtype,         ligature)
223    set_value_entry_key(subtypes_glyph, glyph_math_delimiter_subtype,   delimiter);
224    set_value_entry_key(subtypes_glyph, glyph_math_extensible_subtype,  extensible);
225    set_value_entry_key(subtypes_glyph, glyph_math_ordinary_subtype,    ordinary);
226    set_value_entry_key(subtypes_glyph, glyph_math_operator_subtype,    operator);
227    set_value_entry_key(subtypes_glyph, glyph_math_binary_subtype,      binary);
228    set_value_entry_key(subtypes_glyph, glyph_math_relation_subtype,    relation);
229    set_value_entry_key(subtypes_glyph, glyph_math_open_subtype,        open);
230    set_value_entry_key(subtypes_glyph, glyph_math_close_subtype,       close);
231    set_value_entry_key(subtypes_glyph, glyph_math_punctuation_subtype, punctuation);
232    set_value_entry_key(subtypes_glyph, glyph_math_variable_subtype,    variable);
233    set_value_entry_key(subtypes_glyph, glyph_math_active_subtype,      active);
234    set_value_entry_key(subtypes_glyph, glyph_math_inner_subtype,       inner);
235    set_value_entry_key(subtypes_glyph, glyph_math_over_subtype,        over);
236    set_value_entry_key(subtypes_glyph, glyph_math_under_subtype,       under);
237    set_value_entry_key(subtypes_glyph, glyph_math_fraction_subtype,    fraction);
238    set_value_entry_key(subtypes_glyph, glyph_math_radical_subtype,     radical);
239    set_value_entry_key(subtypes_glyph, glyph_math_middle_subtype,      middle);
240    set_value_entry_key(subtypes_glyph, glyph_math_accent_subtype,      accent);
241
242    subtypes_disc = lmt_aux_allocate_value_info(syllable_discretionary_code);
243
244    set_value_entry_key(subtypes_disc, normal_discretionary_code,      discretionary)
245    set_value_entry_key(subtypes_disc, explicit_discretionary_code,    explicit)
246    set_value_entry_key(subtypes_disc, automatic_discretionary_code,   automatic)
247    set_value_entry_key(subtypes_disc, mathematics_discretionary_code, math)
248    set_value_entry_key(subtypes_disc, syllable_discretionary_code,    regular)
249
250    subtypes_fence = lmt_aux_allocate_value_info(no_fence_side);
251
252    set_value_entry_key(subtypes_fence, unset_fence_side,    unset)
253    set_value_entry_key(subtypes_fence, left_fence_side,     left)
254    set_value_entry_key(subtypes_fence, middle_fence_side,   middle)
255    set_value_entry_key(subtypes_fence, right_fence_side,    right)
256    set_value_entry_key(subtypes_fence, left_operator_side,  operator)
257    set_value_entry_key(subtypes_fence, no_fence_side,       no)
258
259    subtypes_list = lmt_aux_allocate_value_info(local_middle_list);
260
261    set_value_entry_key(subtypes_list, unknown_list,              unknown)
262    set_value_entry_key(subtypes_list, line_list,                 line)
263    set_value_entry_key(subtypes_list, hbox_list,                 box)
264    set_value_entry_key(subtypes_list, indent_list,               indent)
265    set_value_entry_key(subtypes_list, container_list,            container)
266    set_value_entry_key(subtypes_list, align_row_list,            alignment)
267    set_value_entry_key(subtypes_list, align_cell_list,           cell)
268    set_value_entry_key(subtypes_list, equation_list,             equation)
269    set_value_entry_key(subtypes_list, equation_number_list,      equationnumber)
270    set_value_entry_key(subtypes_list, math_list_list,            math)
271    set_value_entry_key(subtypes_list, math_pack_list,            mathpack)
272    set_value_entry_key(subtypes_list, math_char_list,            mathchar)
273    set_value_entry_key(subtypes_list, math_h_extensible_list,    hextensible)
274    set_value_entry_key(subtypes_list, math_v_extensible_list,    vextensible)
275    set_value_entry_key(subtypes_list, math_h_delimiter_list,     hdelimiter)
276    set_value_entry_key(subtypes_list, math_v_delimiter_list,     vdelimiter)
277    set_value_entry_key(subtypes_list, math_over_delimiter_list,  overdelimiter)
278    set_value_entry_key(subtypes_list, math_under_delimiter_list, underdelimiter)
279    set_value_entry_key(subtypes_list, math_numerator_list,       numerator)
280    set_value_entry_key(subtypes_list, math_denominator_list,     denominator)
281    set_value_entry_key(subtypes_list, math_modifier_list,        modifier)
282    set_value_entry_key(subtypes_list, math_fraction_list,        fraction)
283    set_value_entry_key(subtypes_list, math_nucleus_list,         nucleus)
284    set_value_entry_key(subtypes_list, math_sup_list,             sup)
285    set_value_entry_key(subtypes_list, math_sub_list,             sub)
286    set_value_entry_key(subtypes_list, math_pre_post_list,        prepost)
287    set_value_entry_key(subtypes_list, math_degree_list,          degree)
288    set_value_entry_key(subtypes_list, math_scripts_list,         scripts)
289    set_value_entry_key(subtypes_list, math_over_list,            over)
290    set_value_entry_key(subtypes_list, math_under_list,           under)
291    set_value_entry_key(subtypes_list, math_accent_list,          accent)
292    set_value_entry_key(subtypes_list, math_radical_list,         radical)
293    set_value_entry_key(subtypes_list, math_fence_list,           fence)
294    set_value_entry_key(subtypes_list, math_rule_list,            rule)
295    set_value_entry_key(subtypes_list, math_ghost_list,           ghost)
296    set_value_entry_key(subtypes_list, insert_result_list,        insert)
297    set_value_entry_key(subtypes_list, local_list,                local)
298    set_value_entry_key(subtypes_list, local_left_list,           left)
299    set_value_entry_key(subtypes_list, local_right_list,          right)
300    set_value_entry_key(subtypes_list, local_middle_list,         middle)
301
302    subtypes_math = lmt_aux_allocate_value_info(end_inline_math);
303
304    set_value_entry_key(subtypes_math, begin_inline_math, beginmath)
305    set_value_entry_key(subtypes_math, end_inline_math,   endmath)
306
307    subtypes_adjust = lmt_aux_allocate_value_info(local_adjust_code);
308
309    set_value_entry_key(subtypes_adjust, pre_adjust_code,   pre)
310    set_value_entry_key(subtypes_adjust, post_adjust_code,  post)
311    set_value_entry_key(subtypes_adjust, local_adjust_code, local)
312
313    subtypes_mark = lmt_aux_allocate_value_info(reset_mark_value_code);
314
315    set_value_entry_key(subtypes_mark, set_mark_value_code,   set)
316    set_value_entry_key(subtypes_mark, reset_mark_value_code, reset)
317
318    subtypes_noad = lmt_aux_allocate_value_info(vcenter_noad_subtype); // last_noad_subtype
319
320    set_value_entry_key(subtypes_noad, ordinary_noad_subtype,    ordinary)
321    set_value_entry_key(subtypes_noad, operator_noad_subtype,    operator)
322    set_value_entry_key(subtypes_noad, binary_noad_subtype,      binary)
323    set_value_entry_key(subtypes_noad, relation_noad_subtype,    relation)
324    set_value_entry_key(subtypes_noad, open_noad_subtype,        open)
325    set_value_entry_key(subtypes_noad, close_noad_subtype,       close)
326    set_value_entry_key(subtypes_noad, punctuation_noad_subtype, punctuation)
327    set_value_entry_key(subtypes_noad, variable_noad_subtype,    variable)
328    set_value_entry_key(subtypes_noad, active_noad_subtype,      active)
329    set_value_entry_key(subtypes_noad, inner_noad_subtype,       inner)
330    set_value_entry_key(subtypes_noad, under_noad_subtype,       under)
331    set_value_entry_key(subtypes_noad, over_noad_subtype,        over)
332    set_value_entry_key(subtypes_noad, fraction_noad_subtype,    fraction)
333    set_value_entry_key(subtypes_noad, radical_noad_subtype,     radical)
334    set_value_entry_key(subtypes_noad, middle_noad_subtype,      middle)
335    set_value_entry_key(subtypes_noad, accent_noad_subtype,      accent)
336    set_value_entry_key(subtypes_noad, fenced_noad_subtype,      fenced)
337    set_value_entry_key(subtypes_noad, ghost_noad_subtype,       ghost)
338    set_value_entry_key(subtypes_noad, vcenter_noad_subtype,     vcenter)
339
340    subtypes_choice = lmt_aux_allocate_value_info(discretionary_choice_subtype);
341
342    set_value_entry_key(subtypes_choice, normal_choice_subtype,        normal)
343    set_value_entry_key(subtypes_choice, discretionary_choice_subtype, discretionary)
344
345    subtypes_radical = lmt_aux_allocate_value_info(h_extensible_radical_subtype);
346
347    set_value_entry_key(subtypes_radical, normal_radical_subtype,          normal)
348    set_value_entry_key(subtypes_radical, radical_radical_subtype,         radical)
349    set_value_entry_key(subtypes_radical, root_radical_subtype,            root)
350    set_value_entry_key(subtypes_radical, rooted_radical_subtype,          rooted)
351    set_value_entry_key(subtypes_radical, under_delimiter_radical_subtype, underdelimiter)
352    set_value_entry_key(subtypes_radical, over_delimiter_radical_subtype,  overdelimiter)
353    set_value_entry_key(subtypes_radical, delimiter_under_radical_subtype, delimiterunder)
354    set_value_entry_key(subtypes_radical, delimiter_over_radical_subtype,  delimiterover)
355    set_value_entry_key(subtypes_radical, delimited_radical_subtype,       delimited)
356    set_value_entry_key(subtypes_radical, h_extensible_radical_subtype,    hextensible)
357
358    subtypes_accent = lmt_aux_allocate_value_info(fixedboth_accent_subtype);
359
360    set_value_entry_key(subtypes_accent, bothflexible_accent_subtype, bothflexible)
361    set_value_entry_key(subtypes_accent, fixedtop_accent_subtype,     fixedtop)
362    set_value_entry_key(subtypes_accent, fixedbottom_accent_subtype,  fixedbottom)
363    set_value_entry_key(subtypes_accent, fixedboth_accent_subtype,    fixedboth)
364
365    subtypes_attribute = lmt_aux_allocate_value_info(attribute_value_subtype);
366
367    set_value_entry_key(subtypes_attribute, attribute_list_subtype,  list)
368    set_value_entry_key(subtypes_attribute, attribute_value_subtype, value)
369
370    /*tex The fields of nodes. */
371
372    lmt_node_fields_accent = lmt_aux_allocate_value_info(9);
373
374    set_value_entry_val(lmt_node_fields_accent, 0, attribute_field, attr);
375    set_value_entry_val(lmt_node_fields_accent, 1, node_list_field, nucleus);
376    set_value_entry_val(lmt_node_fields_accent, 2, node_list_field, sub);
377    set_value_entry_val(lmt_node_fields_accent, 3, node_list_field, sup);
378    set_value_entry_val(lmt_node_fields_accent, 4, node_list_field, accent);
379    set_value_entry_val(lmt_node_fields_accent, 5, node_list_field, bottomaccent);
380    set_value_entry_val(lmt_node_fields_accent, 6, node_list_field, topaccent);
381    set_value_entry_val(lmt_node_fields_accent, 7, node_list_field, overlayaccent);
382    set_value_entry_val(lmt_node_fields_accent, 8, node_list_field, fraction);
383
384    lmt_node_fields_adjust = lmt_aux_allocate_value_info(2);
385
386    set_value_entry_val(lmt_node_fields_adjust, 0, attribute_field, attr);
387    set_value_entry_val(lmt_node_fields_adjust, 1, node_list_field, list);
388
389    lmt_node_fields_attribute = lmt_aux_allocate_value_info(4);
390
391    set_value_entry_val(lmt_node_fields_attribute, 0, integer_field, count);
392    set_value_entry_val(lmt_node_fields_attribute, 1, integer_field, data);
393    set_value_entry_val(lmt_node_fields_attribute, 2, integer_field, index);
394    set_value_entry_val(lmt_node_fields_attribute, 3, integer_field, value);
395
396    /* Nothing */
397
398    lmt_node_fields_boundary = lmt_aux_allocate_value_info(2);
399
400    set_value_entry_val(lmt_node_fields_boundary, 0, attribute_field, attr);
401    set_value_entry_val(lmt_node_fields_boundary, 1, integer_field,   data);
402
403    lmt_node_fields_choice = lmt_aux_allocate_value_info(5);
404
405    set_value_entry_val(lmt_node_fields_choice, 0, attribute_field, attr);
406    set_value_entry_val(lmt_node_fields_choice, 1, node_list_field, display);
407    set_value_entry_val(lmt_node_fields_choice, 2, node_list_field, text);
408    set_value_entry_val(lmt_node_fields_choice, 3, node_list_field, script);
409    set_value_entry_val(lmt_node_fields_choice, 4, node_list_field, scriptscript);
410
411    lmt_node_fields_delimiter = lmt_aux_allocate_value_info(5);
412
413    set_value_entry_val(lmt_node_fields_delimiter, 0, attribute_field, attr);
414    set_value_entry_val(lmt_node_fields_delimiter, 1, integer_field,   smallfamily);
415    set_value_entry_val(lmt_node_fields_delimiter, 2, integer_field,   smallchar);
416    set_value_entry_val(lmt_node_fields_delimiter, 3, integer_field,   largefamily);
417    set_value_entry_val(lmt_node_fields_delimiter, 4, integer_field,   largechar);
418
419    lmt_node_fields_dir = lmt_aux_allocate_value_info(3);
420
421    set_value_entry_val(lmt_node_fields_dir, 0, attribute_field, attr);
422    set_value_entry_val(lmt_node_fields_dir, 1, integer_field,   dir);
423    set_value_entry_val(lmt_node_fields_dir, 2, integer_field,   level);
424
425    lmt_node_fields_disc = lmt_aux_allocate_value_info( 6);
426
427    set_value_entry_val(lmt_node_fields_disc, 0, attribute_field, attr);
428    set_value_entry_val(lmt_node_fields_disc, 1, node_list_field, pre);
429    set_value_entry_val(lmt_node_fields_disc, 2, node_list_field, post);
430    set_value_entry_val(lmt_node_fields_disc, 3, node_list_field, replace);
431    set_value_entry_val(lmt_node_fields_disc, 4, integer_field,   penalty);
432    set_value_entry_val(lmt_node_fields_disc, 5, integer_field,   options);
433
434    lmt_node_fields_fence = lmt_aux_allocate_value_info(10);
435
436    set_value_entry_val(lmt_node_fields_fence, 0, attribute_field, attr);
437    set_value_entry_val(lmt_node_fields_fence, 1, node_list_field, delimiter);
438    set_value_entry_val(lmt_node_fields_fence, 2, dimension_field, italic);
439    set_value_entry_val(lmt_node_fields_fence, 3, dimension_field, height);
440    set_value_entry_val(lmt_node_fields_fence, 4, dimension_field, depth);
441    set_value_entry_val(lmt_node_fields_fence, 5, integer_field,   options);
442    set_value_entry_val(lmt_node_fields_fence, 6, integer_field,   class);
443    set_value_entry_val(lmt_node_fields_fence, 7, integer_field,   source);
444    set_value_entry_val(lmt_node_fields_fence, 8, node_list_field, top);
445    set_value_entry_val(lmt_node_fields_fence, 9, node_list_field, bottom);
446
447    lmt_node_fields_fraction = lmt_aux_allocate_value_info(9);
448
449    set_value_entry_val(lmt_node_fields_fraction, 0, attribute_field, attr);
450    set_value_entry_val(lmt_node_fields_fraction, 1, dimension_field, width);
451    set_value_entry_val(lmt_node_fields_fraction, 2, node_list_field, numerator);
452    set_value_entry_val(lmt_node_fields_fraction, 3, node_list_field, denominator);
453    set_value_entry_val(lmt_node_fields_fraction, 4, node_list_field, left);
454    set_value_entry_val(lmt_node_fields_fraction, 5, node_list_field, right);
455    set_value_entry_val(lmt_node_fields_fraction, 6, node_list_field, middle);
456    set_value_entry_val(lmt_node_fields_fraction, 7, integer_field,   fam);
457    set_value_entry_val(lmt_node_fields_fraction, 8, integer_field,   options);
458
459    lmt_node_fields_glue = lmt_aux_allocate_value_info(9);
460
461    set_value_entry_val(lmt_node_fields_glue, 0, attribute_field, attr);
462    set_value_entry_val(lmt_node_fields_glue, 1, node_list_field, leader);
463    set_value_entry_val(lmt_node_fields_glue, 2, dimension_field, width);
464    set_value_entry_val(lmt_node_fields_glue, 3, dimension_field, stretch);
465    set_value_entry_val(lmt_node_fields_glue, 4, dimension_field, shrink);
466    set_value_entry_val(lmt_node_fields_glue, 5, integer_field,   stretchorder);
467    set_value_entry_val(lmt_node_fields_glue, 6, integer_field,   shrinkorder);
468    set_value_entry_val(lmt_node_fields_glue, 7, integer_field,   font);
469    set_value_entry_val(lmt_node_fields_glue, 8, integer_field,   options);
470
471    lmt_node_fields_glue_spec = lmt_aux_allocate_value_info(5);
472
473    set_value_entry_val(lmt_node_fields_glue_spec, 0, dimension_field, width);
474    set_value_entry_val(lmt_node_fields_glue_spec, 1, dimension_field, stretch);
475    set_value_entry_val(lmt_node_fields_glue_spec, 2, dimension_field, shrink);
476    set_value_entry_val(lmt_node_fields_glue_spec, 3, integer_field,   stretchorder);
477    set_value_entry_val(lmt_node_fields_glue_spec, 4, integer_field,   shrinkorder);
478
479    lmt_node_fields_glyph = lmt_aux_allocate_value_info(27);
480
481    set_value_entry_val(lmt_node_fields_glyph,  0, attribute_field, attr);
482    set_value_entry_val(lmt_node_fields_glyph,  1, integer_field,   char);
483    set_value_entry_val(lmt_node_fields_glyph,  2, integer_field,   font);
484    set_value_entry_val(lmt_node_fields_glyph,  3, integer_field,   language);
485    set_value_entry_val(lmt_node_fields_glyph,  4, integer_field,   lhmin);
486    set_value_entry_val(lmt_node_fields_glyph,  5, integer_field,   rhmin);
487    set_value_entry_val(lmt_node_fields_glyph,  6, integer_field,   uchyph);
488    set_value_entry_val(lmt_node_fields_glyph,  7, integer_field,   state);
489    set_value_entry_val(lmt_node_fields_glyph,  8, dimension_field, left);
490    set_value_entry_val(lmt_node_fields_glyph,  9, dimension_field, right);
491    set_value_entry_val(lmt_node_fields_glyph, 10, dimension_field, xoffset);
492    set_value_entry_val(lmt_node_fields_glyph, 11, dimension_field, yoffset);
493    set_value_entry_val(lmt_node_fields_glyph, 12, dimension_field, xscale);
494    set_value_entry_val(lmt_node_fields_glyph, 13, dimension_field, yscale);
495    set_value_entry_val(lmt_node_fields_glyph, 14, dimension_field, width);
496    set_value_entry_val(lmt_node_fields_glyph, 15, dimension_field, height);
497    set_value_entry_val(lmt_node_fields_glyph, 16, dimension_field, depth);
498    set_value_entry_val(lmt_node_fields_glyph, 17, dimension_field, total);
499    set_value_entry_val(lmt_node_fields_glyph, 18, integer_field,   expansion);
500    set_value_entry_val(lmt_node_fields_glyph, 19, integer_field,   data);
501    set_value_entry_val(lmt_node_fields_glyph, 20, integer_field,   script);
502    set_value_entry_val(lmt_node_fields_glyph, 21, integer_field,   hyphenate);
503    set_value_entry_val(lmt_node_fields_glyph, 22, integer_field,   options);
504    set_value_entry_val(lmt_node_fields_glyph, 23, integer_field,   protected);
505    set_value_entry_val(lmt_node_fields_glyph, 24, integer_field,   properties);
506    set_value_entry_val(lmt_node_fields_glyph, 25, integer_field,   group);
507    set_value_entry_val(lmt_node_fields_glyph, 26, integer_field,   index);
508
509    lmt_node_fields_insert = lmt_aux_allocate_value_info(6);
510
511    set_value_entry_val(lmt_node_fields_insert, 0, attribute_field, attr);
512    set_value_entry_val(lmt_node_fields_insert, 1, integer_field,   cost);
513    set_value_entry_val(lmt_node_fields_insert, 2, dimension_field, depth);
514    set_value_entry_val(lmt_node_fields_insert, 3, dimension_field, height);
515    set_value_entry_val(lmt_node_fields_insert, 4, integer_field,   spec);
516    set_value_entry_val(lmt_node_fields_insert, 5, node_list_field, list);
517
518    lmt_node_fields_split = lmt_aux_allocate_value_info(6);
519
520    set_value_entry_val(lmt_node_fields_split, 0, attribute_field, height);
521    set_value_entry_val(lmt_node_fields_split, 1, integer_field,   index);
522    set_value_entry_val(lmt_node_fields_split, 2, node_field,      lastinsert);
523    set_value_entry_val(lmt_node_fields_split, 3, node_field,      bestinsert);
524    set_value_entry_val(lmt_node_fields_split, 4, integer_field,   stretchorder);
525    set_value_entry_val(lmt_node_fields_split, 5, integer_field,   shrinkorder);
526
527    lmt_node_fields_kern = lmt_aux_allocate_value_info(3);
528
529    set_value_entry_val(lmt_node_fields_kern, 0, attribute_field, attr);
530    set_value_entry_val(lmt_node_fields_kern, 1, dimension_field, kern);
531    set_value_entry_val(lmt_node_fields_kern, 2, integer_field,   expansion);
532
533    lmt_node_fields_list = lmt_aux_allocate_value_info(20);
534
535    set_value_entry_val(lmt_node_fields_list,  0, attribute_field, attr);
536    set_value_entry_val(lmt_node_fields_list,  1, dimension_field, width);
537    set_value_entry_val(lmt_node_fields_list,  2, dimension_field, depth);
538    set_value_entry_val(lmt_node_fields_list,  3, dimension_field, height);
539    set_value_entry_val(lmt_node_fields_list,  4, integer_field,   direction);
540    set_value_entry_val(lmt_node_fields_list,  5, dimension_field, shift);
541    set_value_entry_val(lmt_node_fields_list,  6, integer_field,   glueorder);
542    set_value_entry_val(lmt_node_fields_list,  7, integer_field,   gluesign);
543    set_value_entry_val(lmt_node_fields_list,  8, integer_field,   glueset);
544    set_value_entry_val(lmt_node_fields_list,  9, node_list_field, list);
545    set_value_entry_val(lmt_node_fields_list, 10, integer_field,   orientation);
546    set_value_entry_val(lmt_node_fields_list, 11, integer_field,   source);
547    set_value_entry_val(lmt_node_fields_list, 12, integer_field,   target);
548    set_value_entry_val(lmt_node_fields_list, 13, dimension_field, woffset);
549    set_value_entry_val(lmt_node_fields_list, 14, dimension_field, hoffset);
550    set_value_entry_val(lmt_node_fields_list, 15, dimension_field, doffset);
551    set_value_entry_val(lmt_node_fields_list, 16, dimension_field, xoffset);
552    set_value_entry_val(lmt_node_fields_list, 17, dimension_field, yoffset);
553    set_value_entry_val(lmt_node_fields_list, 18, integer_field,   state);
554    set_value_entry_val(lmt_node_fields_list, 19, integer_field,   class);
555
556    lmt_node_fields_par = lmt_aux_allocate_value_info(9);
557    set_value_entry_val(lmt_node_fields_par, 0, attribute_field, attr);
558    set_value_entry_val(lmt_node_fields_par, 1, integer_field,   interlinepenalty);
559    set_value_entry_val(lmt_node_fields_par, 2, integer_field,   brokenpenalty);
560    set_value_entry_val(lmt_node_fields_par, 3, integer_field,   dir);
561    set_value_entry_val(lmt_node_fields_par, 4, node_field,      leftbox);
562    set_value_entry_val(lmt_node_fields_par, 5, dimension_field, leftboxwidth);
563    set_value_entry_val(lmt_node_fields_par, 6, node_field,      rightbox);
564    set_value_entry_val(lmt_node_fields_par, 7, dimension_field, rightboxwidth);
565    set_value_entry_val(lmt_node_fields_par, 8, node_field,      middlebox);
566
567    lmt_node_fields_mark = lmt_aux_allocate_value_info(3);
568
569    set_value_entry_val(lmt_node_fields_mark, 0, attribute_field,  attr);
570    set_value_entry_val(lmt_node_fields_mark, 1, integer_field,    class);
571    set_value_entry_val(lmt_node_fields_mark, 2, token_list_field, mark);
572
573    lmt_node_fields_math = lmt_aux_allocate_value_info(9);
574
575    set_value_entry_val(lmt_node_fields_math, 0, attribute_field, attr);
576    set_value_entry_val(lmt_node_fields_math, 1, integer_field,   surround);
577    set_value_entry_val(lmt_node_fields_math, 2, dimension_field, width);
578    set_value_entry_val(lmt_node_fields_math, 3, dimension_field, stretch);
579    set_value_entry_val(lmt_node_fields_math, 4, dimension_field, shrink);
580    set_value_entry_val(lmt_node_fields_math, 5, integer_field,   stretchorder);
581    set_value_entry_val(lmt_node_fields_math, 6, integer_field,   shrinkorder);
582    set_value_entry_val(lmt_node_fields_math, 7, integer_field,   penalty);
583    set_value_entry_val(lmt_node_fields_glue, 8, integer_field,   options);
584
585    lmt_node_fields_math_char = lmt_aux_allocate_value_info(7);
586
587    set_value_entry_val(lmt_node_fields_math_char, 0, attribute_field, attr);
588    set_value_entry_val(lmt_node_fields_math_char, 1, integer_field,   fam);
589    set_value_entry_val(lmt_node_fields_math_char, 2, integer_field,   char);
590    set_value_entry_val(lmt_node_fields_math_char, 3, integer_field,   options);
591    set_value_entry_val(lmt_node_fields_math_char, 4, integer_field,   properties);
592    set_value_entry_val(lmt_node_fields_math_char, 5, integer_field,   group);
593    set_value_entry_val(lmt_node_fields_math_char, 6, integer_field,   index);
594
595    lmt_node_fields_math_text_char = lmt_aux_allocate_value_info(4);
596
597    set_value_entry_val(lmt_node_fields_math_text_char, 0, attribute_field, attr);
598    set_value_entry_val(lmt_node_fields_math_text_char, 1, integer_field,   fam);
599    set_value_entry_val(lmt_node_fields_math_text_char, 2, integer_field,   char);
600    set_value_entry_val(lmt_node_fields_math_text_char, 3, integer_field,   options);
601
602    lmt_node_fields_noad = lmt_aux_allocate_value_info(8);
603
604    set_value_entry_val(lmt_node_fields_noad, 0, attribute_field, attr);
605    set_value_entry_val(lmt_node_fields_noad, 1, node_list_field, nucleus);
606    set_value_entry_val(lmt_node_fields_noad, 2, node_list_field, sub);
607    set_value_entry_val(lmt_node_fields_noad, 3, node_list_field, sup);
608    set_value_entry_val(lmt_node_fields_noad, 4, node_list_field, subpre);
609    set_value_entry_val(lmt_node_fields_noad, 5, node_list_field, suppre);
610    set_value_entry_val(lmt_node_fields_noad, 6, node_list_field, prime);
611    set_value_entry_val(lmt_node_fields_noad, 7, integer_field,   options);
612
613    lmt_node_fields_penalty = lmt_aux_allocate_value_info(2);
614
615    set_value_entry_val(lmt_node_fields_penalty, 0, attribute_field, attr);
616    set_value_entry_val(lmt_node_fields_penalty, 1, integer_field,   penalty);
617
618    lmt_node_fields_radical = lmt_aux_allocate_value_info(11);
619
620    set_value_entry_val(lmt_node_fields_radical,  0, attribute_field, attr);
621    set_value_entry_val(lmt_node_fields_radical,  1, node_list_field, nucleus);
622    set_value_entry_val(lmt_node_fields_radical,  2, node_list_field, sub);
623    set_value_entry_val(lmt_node_fields_radical,  3, node_list_field, sup);
624    set_value_entry_val(lmt_node_fields_radical,  4, node_list_field, presub);
625    set_value_entry_val(lmt_node_fields_radical,  5, node_list_field, presup);
626    set_value_entry_val(lmt_node_fields_radical,  6, node_list_field, prime);
627    set_value_entry_val(lmt_node_fields_radical,  7, node_list_field, left);
628    set_value_entry_val(lmt_node_fields_radical,  8, node_list_field, degree);
629    set_value_entry_val(lmt_node_fields_radical,  9, dimension_field, width);
630    set_value_entry_val(lmt_node_fields_radical, 10, integer_field,   options);
631
632    lmt_node_fields_rule = lmt_aux_allocate_value_info(11);
633
634    set_value_entry_val(lmt_node_fields_rule,  0, attribute_field, attr);
635    set_value_entry_val(lmt_node_fields_rule,  1, dimension_field, width);
636    set_value_entry_val(lmt_node_fields_rule,  2, dimension_field, depth);
637    set_value_entry_val(lmt_node_fields_rule,  3, dimension_field, height);
638    set_value_entry_val(lmt_node_fields_rule,  4, dimension_field, xoffset);
639    set_value_entry_val(lmt_node_fields_rule,  5, dimension_field, yoffset);
640    set_value_entry_val(lmt_node_fields_rule,  6, dimension_field, left);
641    set_value_entry_val(lmt_node_fields_rule,  7, dimension_field, right);
642    set_value_entry_val(lmt_node_fields_rule,  8, integer_field,   data);
643    set_value_entry_val(lmt_node_fields_rule,  9, integer_field,   char);
644    set_value_entry_val(lmt_node_fields_rule, 10, integer_field,   font);
645
646    lmt_node_fields_style = lmt_aux_allocate_value_info(2);
647
648    set_value_entry_val(lmt_node_fields_style, 0, attribute_field, attr);
649    set_value_entry_val(lmt_node_fields_style, 1, integer_field,   style);
650
651    lmt_node_fields_parameter = lmt_aux_allocate_value_info(4);
652
653    set_value_entry_val(lmt_node_fields_parameter, 0, integer_field,   style);
654    set_value_entry_val(lmt_node_fields_parameter, 1, integer_field,   name);
655    set_value_entry_val(lmt_node_fields_parameter, 2, integer_field,   value);
656    set_value_entry_val(lmt_node_fields_parameter, 3, node_list_field, list);
657
658    lmt_node_fields_sub_box = lmt_aux_allocate_value_info(2);
659
660    set_value_entry_val(lmt_node_fields_sub_box, 0, attribute_field, attr);
661    set_value_entry_val(lmt_node_fields_sub_box, 1, node_list_field, list);
662
663    lmt_node_fields_sub_mlist = lmt_aux_allocate_value_info(2);
664
665    set_value_entry_val(lmt_node_fields_sub_mlist, 0, attribute_field, attr);
666    set_value_entry_val(lmt_node_fields_sub_mlist, 1, node_list_field, list);
667
668    lmt_node_fields_unset = lmt_aux_allocate_value_info(11);
669
670    set_value_entry_val(lmt_node_fields_unset,  0, attribute_field, attr);
671    set_value_entry_val(lmt_node_fields_unset,  1, dimension_field, width);
672    set_value_entry_val(lmt_node_fields_unset,  2, dimension_field, depth);
673    set_value_entry_val(lmt_node_fields_unset,  3, dimension_field, height);
674    set_value_entry_val(lmt_node_fields_unset,  4, integer_field,   dir);
675    set_value_entry_val(lmt_node_fields_unset,  5, dimension_field, shrink);
676    set_value_entry_val(lmt_node_fields_unset,  6, integer_field,   glueorder);
677    set_value_entry_val(lmt_node_fields_unset,  7, integer_field,   gluesign);
678    set_value_entry_val(lmt_node_fields_unset,  8, dimension_field, stretch);
679    set_value_entry_val(lmt_node_fields_unset,  9, integer_field,   span);
680    set_value_entry_val(lmt_node_fields_unset, 10, node_list_field, list);
681
682    lmt_node_fields_whatsit = lmt_aux_allocate_value_info(1);
683
684    set_value_entry_val(lmt_node_fields_whatsit, 0, attribute_field, attr);
685
686    lmt_interface.node_data = lmt_memory_malloc((passive_node + 2) * sizeof(node_info));
687
688    /*tex
689        We start with the nodes that users can encounter. The order is mostly the one that \TEX\
690        uses but we have move some around because we have some more and sometimes a bit different
691        kind of nodes. You should use abstractions anyway, so numbers mean nothing. In original
692        \TEX\ there are sometimes tests like |if (foo < kern_node)| but these have been replaces
693        by switches and (un)equality tests so that the order is not really important.
694
695        Subtypes in nodes and codes in commands sometimes are sort of in sync but don't rely on
696        that!
697    */
698
699    lmt_interface.node_data[hlist_node]          = (node_info) { .id = hlist_node,          .size = box_node_size,            .first = 0, .last = last_list_subtype,          .subtypes = subtypes_list,     .fields = lmt_node_fields_list,           .name = lua_key(hlist),          .lua = lua_key_index(hlist),           .visible = 1 };
700    lmt_interface.node_data[vlist_node]          = (node_info) { .id = vlist_node,          .size = box_node_size,            .first = 0, .last = last_list_subtype,          .subtypes = subtypes_list,     .fields = lmt_node_fields_list,           .name = lua_key(vlist),          .lua = lua_key_index(vlist),           .visible = 1 };
701    lmt_interface.node_data[rule_node]           = (node_info) { .id = rule_node,           .size = rule_node_size,           .first = 0, .last = last_rule_subtype,          .subtypes = subtypes_rule,     .fields = lmt_node_fields_rule,           .name = lua_key(rule),           .lua = lua_key_index(rule),            .visible = 1 };
702    lmt_interface.node_data[insert_node]         = (node_info) { .id = insert_node,         .size = insert_node_size,         .first = 0, .last = 0,                          .subtypes = NULL,              .fields = lmt_node_fields_insert,         .name = lua_key(insert),         .lua = lua_key_index(insert),          .visible = 1 };
703    lmt_interface.node_data[mark_node]           = (node_info) { .id = mark_node,           .size = mark_node_size,           .first = 0, .last = last_mark_subtype,          .subtypes = subtypes_mark,     .fields = lmt_node_fields_mark,           .name = lua_key(mark),           .lua = lua_key_index(mark),            .visible = 1 };
704    lmt_interface.node_data[adjust_node]         = (node_info) { .id = adjust_node,         .size = adjust_node_size,         .first = 0, .last = last_adjust_subtype,        .subtypes = subtypes_adjust,   .fields = lmt_node_fields_adjust,         .name = lua_key(adjust),         .lua = lua_key_index(adjust),          .visible = 1 };
705    lmt_interface.node_data[boundary_node]       = (node_info) { .id = boundary_node,       .size = boundary_node_size,       .first = 0, .last = last_boundary_subtype,      .subtypes = subtypes_boundary, .fields = lmt_node_fields_boundary,       .name = lua_key(boundary),       .lua = lua_key_index(boundary),        .visible = 1 };
706    lmt_interface.node_data[disc_node]           = (node_info) { .id = disc_node,           .size = disc_node_size,           .first = 0, .last = last_discretionary_subtype, .subtypes = subtypes_disc,     .fields = lmt_node_fields_disc,           .name = lua_key(disc),           .lua = lua_key_index(disc),            .visible = 1 };
707    lmt_interface.node_data[whatsit_node]        = (node_info) { .id = whatsit_node,        .size = whatsit_node_size,        .first = 0, .last = 0,                          .subtypes = NULL,              .fields = lmt_node_fields_whatsit,        .name = lua_key(whatsit),        .lua = lua_key_index(whatsit),         .visible = 1 };
708    lmt_interface.node_data[par_node]            = (node_info) { .id = par_node,            .size = par_node_size,            .first = 0, .last = last_par_subtype,           .subtypes = subtypes_par,      .fields = lmt_node_fields_par,            .name = lua_key(par),            .lua = lua_key_index(par),             .visible = 1 };
709    lmt_interface.node_data[dir_node]            = (node_info) { .id = dir_node,            .size = dir_node_size,            .first = 0, .last = last_dir_subtype,           .subtypes = subtypes_dir,      .fields = lmt_node_fields_dir,            .name = lua_key(dir),            .lua = lua_key_index(dir),             .visible = 1 };
710    lmt_interface.node_data[math_node]           = (node_info) { .id = math_node,           .size = math_node_size,           .first = 0, .last = last_math_subtype,          .subtypes = subtypes_math,     .fields = lmt_node_fields_math,           .name = lua_key(math),           .lua = lua_key_index(math),            .visible = 1 };
711    lmt_interface.node_data[glue_node]           = (node_info) { .id = glue_node,           .size = glue_node_size,           .first = 0, .last = last_glue_subtype,          .subtypes = subtypes_glue,     .fields = lmt_node_fields_glue,           .name = lua_key(glue),           .lua = lua_key_index(glue),            .visible = 1 };
712    lmt_interface.node_data[kern_node]           = (node_info) { .id = kern_node,           .size = kern_node_size,           .first = 0, .last = last_kern_subtype,          .subtypes = subtypes_kern,     .fields = lmt_node_fields_kern,           .name = lua_key(kern),           .lua = lua_key_index(kern),            .visible = 1 };
713    lmt_interface.node_data[penalty_node]        = (node_info) { .id = penalty_node,        .size = penalty_node_size,        .first = 0, .last = last_penalty_subtype,       .subtypes = subtypes_penalty,  .fields = lmt_node_fields_penalty,        .name = lua_key(penalty),        .lua = lua_key_index(penalty),         .visible = 1 };
714    lmt_interface.node_data[style_node]          = (node_info) { .id = style_node,          .size = style_node_size,          .first = 0, .last = 0,                          .subtypes = NULL,              .fields = lmt_node_fields_style,          .name = lua_key(style),          .lua = lua_key_index(style),           .visible = 1 };
715    lmt_interface.node_data[choice_node]         = (node_info) { .id = choice_node,         .size = choice_node_size,         .first = 0, .last = last_choice_subtype,        .subtypes = subtypes_choice,   .fields = lmt_node_fields_choice,         .name = lua_key(choice),         .lua = lua_key_index(choice),          .visible = 1 };
716    lmt_interface.node_data[parameter_node]      = (node_info) { .id = parameter_node,      .size = parameter_node_size,      .first = 0, .last = 0,                          .subtypes = NULL,              .fields = lmt_node_fields_parameter,      .name = lua_key(parameter),      .lua = lua_key_index(parameter),       .visible = 1 };
717    lmt_interface.node_data[simple_noad]         = (node_info) { .id = simple_noad,         .size = noad_size,                .first = 0, .last = last_noad_subtype,          .subtypes = subtypes_noad,     .fields = lmt_node_fields_noad,           .name = lua_key(noad),           .lua = lua_key_index(noad),            .visible = 1 };
718    lmt_interface.node_data[radical_noad]        = (node_info) { .id = radical_noad,        .size = radical_noad_size,        .first = 0, .last = last_radical_subtype,       .subtypes = subtypes_radical,  .fields = lmt_node_fields_radical,        .name = lua_key(radical),        .lua = lua_key_index(radical),         .visible = 1 };
719    lmt_interface.node_data[fraction_noad]       = (node_info) { .id = fraction_noad,       .size = fraction_noad_size,       .first = 0, .last = 0,                          .subtypes = NULL,              .fields = lmt_node_fields_fraction,       .name = lua_key(fraction),       .lua = lua_key_index(fraction),        .visible = 1 };
720    lmt_interface.node_data[accent_noad]         = (node_info) { .id = accent_noad,         .size = accent_noad_size,         .first = 0, .last = last_accent_subtype,        .subtypes = subtypes_accent,   .fields = lmt_node_fields_accent,         .name = lua_key(accent),         .lua = lua_key_index(accent),          .visible = 1 };
721    lmt_interface.node_data[fence_noad]          = (node_info) { .id = fence_noad,          .size = fence_noad_size,          .first = 0, .last = last_fence_subtype,         .subtypes = subtypes_fence,    .fields = lmt_node_fields_fence,          .name = lua_key(fence),          .lua = lua_key_index(fence),           .visible = 1 };
722    lmt_interface.node_data[math_char_node]      = (node_info) { .id = math_char_node,      .size = math_kernel_node_size,    .first = 0, .last = 0,                          .subtypes = NULL,              .fields = lmt_node_fields_math_char,      .name = lua_key(mathchar),       .lua = lua_key_index(mathchar),        .visible = 1 };
723    lmt_interface.node_data[math_text_char_node] = (node_info) { .id = math_text_char_node, .size = math_kernel_node_size,    .first = 0, .last = 0,                          .subtypes = NULL,              .fields = lmt_node_fields_math_text_char, .name = lua_key(mathtextchar),   .lua = lua_key_index(mathtextchar),    .visible = 1 };
724    lmt_interface.node_data[sub_box_node]        = (node_info) { .id = sub_box_node,        .size = math_kernel_node_size,    .first = 0, .last = 0,                          .subtypes = NULL,              .fields = lmt_node_fields_sub_box,        .name = lua_key(subbox),         .lua = lua_key_index(subbox),          .visible = 1 };
725    lmt_interface.node_data[sub_mlist_node]      = (node_info) { .id = sub_mlist_node,      .size = math_kernel_node_size,    .first = 0, .last = 0,                          .subtypes = NULL,              .fields = lmt_node_fields_sub_mlist,      .name = lua_key(submlist),       .lua = lua_key_index(submlist),        .visible = 1 };
726    lmt_interface.node_data[delimiter_node]      = (node_info) { .id = delimiter_node,      .size = math_delimiter_node_size, .first = 0, .last = 0,                          .subtypes = NULL,              .fields = lmt_node_fields_delimiter,      .name = lua_key(delimiter),      .lua = lua_key_index(delimiter),       .visible = 1 };
727    lmt_interface.node_data[glyph_node]          = (node_info) { .id = glyph_node,          .size = glyph_node_size,          .first = 0, .last = last_glyph_subtype,         .subtypes = subtypes_glyph,    .fields = lmt_node_fields_glyph,          .name = lua_key(glyph),          .lua = lua_key_index(glyph),           .visible = 1 };
728
729    /*tex
730        Who knows when someone needs is, so for now we keep it exposed.
731    */
732
733    lmt_interface.node_data[unset_node]          = (node_info) { .id = unset_node,          .size = box_node_size,            .first = 0, .last = 0,                          .subtypes = NULL,              .fields = lmt_node_fields_unset,          .name = lua_key(unset),          .lua = lua_key_index(unset),           .visible = 1 };
734    lmt_interface.node_data[specification_node]  = (node_info) { .id = specification_node,  .size = specification_node_size,  .first = 0, .last = 0,                          .subtypes = NULL,              .fields = NULL,                           .name = lua_key(specification),  .lua = lua_key_index(specification),   .visible = 0 };
735    lmt_interface.node_data[align_record_node]   = (node_info) { .id = align_record_node,   .size = box_node_size,            .first = 0, .last = 0,                          .subtypes = NULL,              .fields = lmt_node_fields_unset,          .name = lua_key(alignrecord),    .lua = lua_key_index(alignrecord),     .visible = 1 };
736
737    /*tex
738        These nodes never show up in nodelists and are managed special. Messing with such nodes
739        directly is not a good idea.
740    */
741
742    lmt_interface.node_data[attribute_node]      = (node_info) { .id = attribute_node,      .size = attribute_node_size,      .first = 0, .last = last_attribute_subtype,     .subtypes = subtypes_attribute,.fields = lmt_node_fields_attribute,      .name = lua_key(attribute),      .lua = lua_key_index(attribute),       .visible = 1 };
743
744    /*
745        We still expose the glue spec as they are the containers for skip registers but there is no
746        real need to use them at the user end.
747    */
748
749    lmt_interface.node_data[glue_spec_node]      = (node_info) { .id = glue_spec_node,      .size = glue_spec_size,           .first = 0, .last = 0,                          .subtypes = NULL,              .fields = lmt_node_fields_glue_spec,      .name = lua_key(gluespec),       .lua = lua_key_index(gluespec),        .visible = 1 };
750
751    /*tex
752        This one sometimes shows up, especially when we temporarily need an alternative head pointer,
753        simply because we want to retain some head in case the original head is replaced.
754    */
755
756    lmt_interface.node_data[temp_node]           = (node_info) { .id = temp_node,           .size = temp_node_size,           .first = 0, .last = 0,                          .subtypes = NULL,              .fields = NULL,                           .name = lua_key(temp),           .lua = lua_key_index(temp),            .visible = 1 };
757
758    /*tex
759        The split nodes are used for insertions.
760    */
761
762    lmt_interface.node_data[split_node]          = (node_info) { .id = split_node,          .size = split_node_size,          .first = 0, .last = last_split_subtype,         .subtypes = subtypes_split,    .fields = lmt_node_fields_split,          .name = lua_key(split),          .lua = lua_key_index(split),           .visible = 1 };
763
764    /*tex
765        The following nodes are not meant for users. They are used internally for different purposes
766        and you should not encounter them in node lists. As with many nodes, they often are
767        allocated using fast methods so they never show up in the new, copy and flush handlers.
768    */
769
770    lmt_interface.node_data[expression_node]     = (node_info) { .id = expression_node,     .size = expression_node_size,     .first = 0, .last = 0,                         .subtypes = NULL,              .fields = NULL,                           .name = lua_key(expression),     .lua = lua_key_index(expression),      .visible = 0 };
771    lmt_interface.node_data[loop_state_node]     = (node_info) { .id = loop_state_node,     .size = loop_state_node_size,     .first = 0, .last = 0,                         .subtypes = NULL,              .fields = NULL,                           .name = lua_key(loopstate),      .lua = lua_key_index(loopstate),       .visible = 0 };
772    lmt_interface.node_data[math_spec_node]      = (node_info) { .id = math_spec_node,      .size = math_spec_node_size,      .first = 0, .last = 0,                         .subtypes = NULL,              .fields = NULL,                           .name = lua_key(mathspec),       .lua = lua_key_index(mathspec),        .visible = 0 };
773    lmt_interface.node_data[font_spec_node]      = (node_info) { .id = font_spec_node,      .size = font_spec_node_size,      .first = 0, .last = 0,                         .subtypes = NULL,              .fields = NULL,                           .name = lua_key(fontspec),       .lua = lua_key_index(fontspec),        .visible = 0 };
774    lmt_interface.node_data[nesting_node]        = (node_info) { .id = nesting_node,        .size = nesting_node_size,        .first = 0, .last = 0,                         .subtypes = NULL,              .fields = NULL,                           .name = lua_key(nestedlist),     .lua = lua_key_index(nestedlist),      .visible = 0 };
775    lmt_interface.node_data[span_node]           = (node_info) { .id = span_node,           .size = span_node_size,           .first = 0, .last = 0,                         .subtypes = NULL,              .fields = NULL,                           .name = lua_key(span),           .lua = lua_key_index(span),            .visible = 0 };
776    lmt_interface.node_data[align_stack_node]    = (node_info) { .id = align_stack_node,    .size = align_stack_node_size,    .first = 0, .last = 0,                         .subtypes = NULL,              .fields = NULL,                           .name = lua_key(alignstack),     .lua = lua_key_index(alignstack),      .visible = 0 };
777 // lmt_interface.node_data[noad_state_node]     = (node_info) { .id = noad_state_node,     .size = noad_state_node_size,     .first = 0, .last = 0,                         .subtypes = NULL,              .fields = NULL,                           .name = lua_key(noadstate),      .lua = lua_key_index(noadstate),       .visible = 0 };
778    lmt_interface.node_data[if_node]             = (node_info) { .id = if_node,             .size = if_node_size,             .first = 0, .last = 0,                         .subtypes = NULL,              .fields = NULL,                           .name = lua_key(ifstack),        .lua = lua_key_index(ifstack),         .visible = 0 };
779    lmt_interface.node_data[unhyphenated_node]   = (node_info) { .id = unhyphenated_node,   .size = active_node_size,         .first = 0, .last = 0,                         .subtypes = NULL,              .fields = NULL,                           .name = lua_key(unhyphenated),   .lua = lua_key_index(unhyphenated),    .visible = 0 };
780    lmt_interface.node_data[hyphenated_node]     = (node_info) { .id = hyphenated_node,     .size = active_node_size,         .first = 0, .last = 0,                         .subtypes = NULL,              .fields = NULL,                           .name = lua_key(hyphenated),     .lua = lua_key_index(hyphenated),      .visible = 0 };
781    lmt_interface.node_data[delta_node]          = (node_info) { .id = delta_node,          .size = delta_node_size,          .first = 0, .last = 0,                         .subtypes = NULL,              .fields = NULL,                           .name = lua_key(delta),          .lua = lua_key_index(delta),           .visible = 0 };
782    lmt_interface.node_data[passive_node]        = (node_info) { .id = passive_node,        .size = passive_node_size,        .first = 0, .last = 0,                         .subtypes = NULL,              .fields = NULL,                           .name = lua_key(passive),        .lua = lua_key_index(passive),         .visible = 0 };
783    lmt_interface.node_data[passive_node + 1]    = (node_info) { .id = -1,                  .size = -1,                       .first = 0, .last = 0,                         .subtypes = NULL,              .fields = NULL,                           .name = NULL,                    .lua = 0,                              .visible = 0 };
784
785}
786
787/*tex
788
789    When we copy a node list, there are several possibilities: we do the same as a new node, we
790    copy the entry to the table in properties (a reference), we do a deep copy of a table in the
791    properties, we create a new table and give it the original one as a metatable. After some
792    experiments (that also included timing) with these scenarios I decided that a deep copy made no
793    sense, nor did nilling. In the end both the shallow copy and the metatable variant were both
794    okay, although the metatables at that time performed a bit less. The most important aspect to 
795    keep in mind is that references to other nodes in properties no longer can be valid for that 
796    copy. We could use two tables (one unique and one shared) or metatables but that only 
797    complicates matters. Maybe some day I will remove the method that not used in \CONTEXT, just 
798    because switching methods during a run will for sure break things. 
799
800    When defining a new node, we could already allocate a table but it is rather easy to do that at
801    the lua end e.g. using a metatable __index method. That way it is under macro package control.
802
803    When deleting a node, we could keep the slot (e.g. setting it to false) but it could make
804    memory consumption raise unneeded when we have temporary large node lists and after that only
805    small lists.
806
807    So, in the end this is what we ended up with. For the record, I also experimented with the
808    following:
809
810    \startitemize
811
812        \startitem
813            Copy attributes to the properties so that we have fast access at the \LUA\ end: in the
814            end the overhead is not compensated by speed and convenience, in fact, attributes are
815            not that slow when it comes to accessing them.
816        \stopitem
817
818        \startitem
819            A bitset in the node but again the gain compared to attributes is neglectable and it
820            also demands a pretty string agreement over what bit represents what, and this is
821            unlikely to succeed in the tex community (I could use it for font handling, which is
822            cross package, but decided that it doesn't pay off.
823        \stopitem
824
825    \stopitemize
826
827    In case one wonders why properties make sense then, well, it is not so much speed that we gain,
828    but more convenience: storing all kind of (temporary) data in attributes is no fun and this
829    mechanism makes sure that properties are cleaned up when a node is freed. Also, the advantage
830    of a more or less global properties table is that we stay at the \LUA\ end. An alternative is
831    to store a reference in the node itself but that is complicated by the fact that the register
832    has some limitations (no numeric keys) and we also don't want to mess with it too much.
833
834    We keep track of nesting so that we don't overflow the stack, and, what is more important,
835    don't keep resolving the registry index.
836
837    We could add an index field to each node and use that one. But then we'd have to default to
838    false. It actually would look nicer in tracing: indices instead of pseudo memory slots. It
839    would not boost performance. A table like this is never really collected.
840
841*/
842
843inline static void lmt_properties_push(lua_State * L)
844{
845    lmt_node_memory_state.lua_properties_level++;
846    if (lmt_node_memory_state.lua_properties_level == 1) {
847        lua_rawgeti(L, LUA_REGISTRYINDEX, lmt_node_memory_state.node_properties_id);
848    }
849}
850
851inline static void lmt_properties_pop(lua_State * L)
852{
853    if (lmt_node_memory_state.lua_properties_level == 1) {
854        lua_pop(L, 1);
855    }
856    lmt_node_memory_state.lua_properties_level--;
857}
858
859/*tex Resetting boils down to nilling. */
860
861inline static void lmt_properties_reset(lua_State * L, halfword target)
862{
863    if (lmt_node_memory_state.lua_properties_level == 0) {
864        lua_rawgeti(L, LUA_REGISTRYINDEX, lmt_node_memory_state.node_properties_id);
865        lua_pushnil(L);
866        lua_rawseti(L, -2, target);
867        lua_pop(L, 1);
868    } else {
869        lua_pushnil(L);
870        lua_rawseti(L, -2, target);
871    }
872}
873
874inline static void lmt_properties_copy(lua_State *L, halfword target, halfword source)
875{
876    if (lmt_node_memory_state.lua_properties_level == 0) {
877        lua_rawgeti(L, LUA_REGISTRYINDEX, lmt_node_memory_state.node_properties_id);
878    }
879    /* properties */
880    if (lua_rawgeti(L, -1, source) == LUA_TTABLE) {
881        /* properties source */
882        lua_createtable(L, 0, 1);
883        /* properties source {} */
884        lua_insert(L, -2);
885        /* properties {} source */
886        lua_push_key(__index);
887        /* properties {} source "__index" */
888        lua_insert(L, -2);
889        /* properties {} "__index" source  */
890        lua_rawset(L, -3);
891        /* properties {__index=source} */
892        lua_createtable(L, 0, 1);
893        /* properties {__index=source} {} */
894        lua_insert(L, -2);
895        /* properties {} {__index=source} */
896        lua_setmetatable(L, -2);
897        /* properties {}->{__index=source} */
898        lua_rawseti(L, -2, target);
899        /* properties[target]={}->{__index=source} */
900    } else {
901        /* properties nil */
902        lua_pop(L, 1);
903    }
904    /* properties */
905    if (lmt_node_memory_state.lua_properties_level == 0) {
906        lua_pop(L, 1);
907    }
908}
909
910/*tex The public one: */
911
912void tex_reset_node_properties(halfword b)
913{
914    if (b) {
915        lmt_properties_reset(lmt_lua_state.lua_instance, b);
916    }
917}
918
919/*tex Here end the property handlers. */
920
921static void tex_aux_node_range_test(halfword a, halfword b)
922{
923    if (b < 0 || b >= lmt_node_memory_state.nodes_data.allocated) {
924        tex_formatted_error("nodes", "node range test failed in %s node", lmt_interface.node_data[node_type(a)].name);
925    }
926}
927
928/*tex
929
930    Because of the 5-10\% overhead that \SYNTEX\ creates some options have been implemented
931    controlled by |synctex_anyway_mode|.
932
933    \startabulate
934    \NC \type {1} \NC all but glyphs  \NC \NR
935    \NC \type {2} \NC also glyphs     \NC \NR
936    \NC \type {3} \NC glyphs and glue \NC \NR
937    \NC \type {4} \NC only glyphs     \NC \NR
938    \stoptabulate
939
940*/
941
942/*tex |if_stack| is called a lot so maybe optimize that one. */
943
944/*tex This needs a cleanup ... there is no need to store the pointer location itself. */
945
946inline static void tex_aux_preset_disc_node(halfword n)
947{
948    disc_pre_break(n) = disc_pre_break_node(n);
949    disc_post_break(n) = disc_post_break_node(n);
950    disc_no_break(n) = disc_no_break_node(n);
951    node_type(disc_pre_break(n)) = nesting_node;
952    node_type(disc_post_break(n)) = nesting_node;
953    node_type(disc_no_break(n)) = nesting_node;
954    node_subtype(disc_pre_break(n)) = pre_break_code;
955    node_subtype(disc_post_break(n)) = post_break_code;
956    node_subtype(disc_no_break(n)) = no_break_code;
957}
958
959inline static void tex_aux_preset_node(halfword n, quarterword type) 
960{
961    switch (type) { 
962        case glyph_node:
963            break;
964        case hlist_node:
965        case vlist_node:
966            box_dir(n) = direction_unknown;
967            break;
968        case disc_node:
969            tex_aux_preset_disc_node(n);
970            break;
971        case rule_node:
972            rule_width(n) = null_flag;
973            rule_depth(n) = null_flag;
974            rule_height(n) = null_flag;
975            rule_data(n) = 0;
976            break;
977        case unset_node:
978            box_width(n) = null_flag;
979            break;
980        case specification_node:
981            tex_null_specification_list(n);
982            break;
983        case simple_noad:
984        case radical_noad:
985        case fraction_noad:
986        case accent_noad:
987        case fence_noad:
988            noad_family(n) = unused_math_family;
989            noad_style(n) = unused_math_style;
990            reset_noad_classes(n); /* unsets them */
991            break;
992    }
993}
994
995halfword tex_new_node(quarterword type, quarterword subtype)
996{
997    halfword size = get_node_size(type);
998    halfword node = tex_get_node(size);
999
1000    /*tex
1001
1002        Both type() and subtype() will be set below, and node_next() is set to null by |get_node()|,
1003        so we can clear one word less than |s|.
1004
1005    */
1006
1007    memset((void *) (lmt_node_memory_state.nodes + node + 1), 0, (sizeof(memoryword) * ((size_t) size - 1)));
1008
1009    if (tex_nodetype_is_complex(type)) {
1010        tex_aux_preset_node(node, type);
1011        if (input_file_state.mode > 0) {
1012            /*tex See table above. */
1013            switch (type) {
1014                case glyph_node:
1015                    if (input_file_state.mode > 1) {
1016                        glyph_input_file(node) = input_file_value();
1017                        glyph_input_line(node) = input_line_value();
1018                    }
1019                    break;
1020                case hlist_node:
1021                case vlist_node:
1022                case unset_node:
1023                    box_input_file(node) = input_file_value();
1024                    box_input_line(node) = input_line_value();
1025                    break;
1026            }
1027        }
1028        if (tex_nodetype_has_attributes(type)) {
1029            attach_current_attribute_list(node);
1030        }
1031    }
1032    /* last */
1033    node_type(node) = type;
1034    node_subtype(node) = subtype;
1035    return node;
1036}
1037
1038halfword tex_new_temp_node(void)
1039{
1040    halfword n = tex_get_node(temp_node_size);
1041    node_type(n) = temp_node;
1042    node_subtype(n) = 0;
1043    memset((void *) (lmt_node_memory_state.nodes + n + 1), 0, (sizeof(memoryword) * (temp_node_size - 1)));
1044    return n;
1045}
1046
1047static halfword tex_aux_new_glyph_node_with_attributes(halfword parent)
1048{
1049    halfword n = tex_get_node(glyph_node_size);
1050    memset((void *) (lmt_node_memory_state.nodes + n + 1), 0, (sizeof(memoryword) * (glyph_node_size - 1)));
1051    if (input_file_state.mode > 1) {
1052        glyph_input_file(n) = input_file_value();
1053        glyph_input_line(n) = input_line_value();
1054    }
1055    node_type(n) = glyph_node;
1056    node_subtype(n) = glyph_unset_subtype;
1057    if (parent) {
1058        tex_attach_attribute_list_copy(n, parent);
1059    } else {
1060        attach_current_attribute_list(n);
1061    }
1062    return n;
1063}
1064
1065/*tex
1066    This makes a duplicate of the node list that starts at |p| and returns a pointer to the new
1067    list.
1068*/
1069
1070halfword tex_copy_node_list(halfword p, halfword end)
1071{
1072    /*tex head of the list */
1073    halfword h = null;
1074    /*tex previous position in new list */
1075    halfword q = null;
1076    /*tex saves stack and time */
1077    lua_State *L = lmt_lua_state.lua_instance;
1078    lmt_properties_push(L);
1079    while (p != end) {
1080        halfword s = tex_copy_node(p);
1081        if (h) {
1082            tex_couple_nodes(q, s);
1083        } else {
1084            h = s;
1085        }
1086        q = s;
1087        p = node_next(p);
1088    }
1089    /*tex saves stack and time */
1090    lmt_properties_pop(L);
1091    return h;
1092}
1093
1094/*tex Make a dupe of a single node. */
1095
1096halfword tex_copy_node_only(halfword p)
1097{
1098    quarterword t = node_type(p);
1099    int s = get_node_size(t);
1100    halfword r = tex_get_node(s);
1101    memcpy((void *) (lmt_node_memory_state.nodes + r), (void *) (lmt_node_memory_state.nodes + p), (sizeof(memoryword) ));
1102    memset((void *) (lmt_node_memory_state.nodes + r + 1), 0, (sizeof(memoryword) * ((unsigned) s - 1)));
1103    tex_aux_preset_node(r, t); 
1104    return r;
1105}
1106
1107/*tex
1108    We really need to use macros here as we need the temporary variable because varmem can be
1109    reallocated! We cross our fingers that the compiler doesn't optimize that one away. (The test
1110    suite had a few cases where reallocation during a copy happens.) We can make |copy_stub|
1111    local here.
1112 */
1113
1114# define copy_sub_list(target,source) do { \
1115     if (source) { \
1116         halfword copy_stub = tex_copy_node_list(source, null); \
1117         target = copy_stub; \
1118     } else { \
1119         target = null; \
1120     } \
1121 } while (0)
1122
1123# define copy_sub_node(target,source) do { \
1124    if (source) { \
1125        halfword copy_stub = tex_copy_node(source); \
1126        target = copy_stub; \
1127    } else { \
1128        target = null; \
1129    } \
1130} while (0)
1131
1132/*tex 
1133    Checking for |null| doesnot happen here but in the calling routine because zero also means zero 
1134    glue (so that we don't need to have many glue nodes hanging around). In traditional \TEX\ these 
1135    were static shared (ref counted) gluenodes. 
1136*/
1137
1138halfword tex_copy_node(halfword original)
1139{
1140    /*tex
1141        We really need a stub for copying because mem might move in the meantime due to resizing!
1142    */
1143    if (original < 0 || original >= lmt_node_memory_state.nodes_data.allocated) {
1144        return tex_formatted_error("nodes", "attempt to copy an impossible node %d", (int) original);
1145    } else if (original > lmt_node_memory_state.reserved && lmt_node_memory_state.nodesizes[original] == 0) {
1146        return tex_formatted_error("nodes", "attempt to copy a free %s node %d", get_node_name(node_type(original)), (int) original);
1147    } else {
1148        /*tex type of node */
1149        halfword type = node_type(original);
1150        int size = get_node_size(type);
1151        /*tex current node being fabricated for new list */
1152        halfword copy = tex_get_node(size);
1153        /*tex this saves work */
1154        memcpy((void *) (lmt_node_memory_state.nodes + copy), (void *) (lmt_node_memory_state.nodes + original), (sizeof(memoryword) * (unsigned) size));
1155        if (tex_nodetype_is_complex(size)) {
1156            if (tex_nodetype_has_attributes(type)) {
1157                add_attribute_reference(node_attr(original));
1158                node_prev(copy) = null;
1159                lmt_properties_copy(lmt_lua_state.lua_instance, copy, original);
1160            }
1161            node_next(copy) = null;
1162            switch (type) {
1163                case glue_node:
1164                    copy_sub_list(glue_leader_ptr(copy), glue_leader_ptr(original));
1165                    break;
1166                case hlist_node:
1167                    copy_sub_list(box_pre_adjusted(copy), box_pre_adjusted(original));
1168                    copy_sub_list(box_post_adjusted(copy), box_post_adjusted(original));
1169                    // fall through
1170                case vlist_node:
1171                    copy_sub_list(box_pre_migrated(copy), box_pre_migrated(original));
1172                    copy_sub_list(box_post_migrated(copy), box_post_migrated(original));
1173                    // fall through
1174                case unset_node:
1175                    copy_sub_list(box_list(copy), box_list(original));
1176                    break;
1177                case disc_node:
1178                    disc_pre_break(copy) = disc_pre_break_node(copy);
1179                    if (disc_pre_break_head(original)) {
1180                        tex_set_disc_field(copy, pre_break_code, tex_copy_node_list(disc_pre_break_head(original), null));
1181                    } else {
1182                        tex_set_disc_field(copy, pre_break_code, null);
1183                    }
1184                    disc_post_break(copy) = disc_post_break_node(copy);
1185                    if (disc_post_break_head(original)) {
1186                        tex_set_disc_field(copy, post_break_code, tex_copy_node_list(disc_post_break_head(original), null));
1187                    } else {
1188                        tex_set_disc_field(copy, post_break_code, null);
1189                    }
1190                    disc_no_break(copy) = disc_no_break_node(copy);
1191                    if (disc_no_break_head(original)) {
1192                        tex_set_disc_field(copy, no_break_code, tex_copy_node_list(disc_no_break_head(original), null));
1193                    } else {
1194                        tex_set_disc_field(copy, no_break_code, null);
1195                    }
1196                    break;
1197                case insert_node:
1198                    copy_sub_list(insert_list(copy), insert_list(original));
1199                    break;
1200                case mark_node:
1201                    tex_add_token_reference(mark_ptr(original));
1202                    break;
1203                case adjust_node:
1204                    copy_sub_list(adjust_list(copy), adjust_list(original));
1205                    break;
1206                case choice_node:
1207                    copy_sub_list(choice_display_mlist(copy), choice_display_mlist(original));
1208                    copy_sub_list(choice_text_mlist(copy), choice_text_mlist(original));
1209                    copy_sub_list(choice_script_mlist(copy), choice_script_mlist(original));
1210                    copy_sub_list(choice_script_script_mlist(copy), choice_script_script_mlist(original));
1211                    break;
1212                case simple_noad:
1213                case radical_noad:
1214                case fraction_noad:
1215                case accent_noad:
1216                    copy_sub_list(noad_nucleus(copy), noad_nucleus(original));
1217                    copy_sub_list(noad_subscr(copy), noad_subscr(original));
1218                    copy_sub_list(noad_supscr(copy), noad_supscr(original));
1219                    copy_sub_list(noad_subprescr(copy), noad_subprescr(original));
1220                    copy_sub_list(noad_supprescr(copy), noad_supprescr(original));
1221                    copy_sub_list(noad_prime(copy), noad_prime(original));
1222                 // copy_sub_list(noad_state(copy), noad_state(original));
1223                    switch (type) {
1224                        case radical_noad:
1225                            copy_sub_node(radical_left_delimiter(copy), radical_left_delimiter(original));
1226                            copy_sub_node(radical_right_delimiter(copy), radical_right_delimiter(original));
1227                            copy_sub_node(radical_top_delimiter(copy), radical_top_delimiter(original));
1228                            copy_sub_node(radical_bottom_delimiter(copy), radical_bottom_delimiter(original));
1229                            copy_sub_list(radical_degree(copy), radical_degree(original));
1230                            break;
1231                        case fraction_noad:
1232                         // copy_sub_list(fraction_numerator(copy), fraction_numerator(p));
1233                         // copy_sub_list(fraction_denominator(copy), fraction_denominator(p);
1234                            copy_sub_node(fraction_left_delimiter(copy), fraction_left_delimiter(original));
1235                            copy_sub_node(fraction_right_delimiter(copy), fraction_right_delimiter(original));
1236                            copy_sub_node(fraction_middle_delimiter(copy), fraction_middle_delimiter(original));
1237                            break;
1238                        case accent_noad:
1239                            copy_sub_list(accent_top_character(copy), accent_top_character(original));
1240                            copy_sub_list(accent_bottom_character(copy), accent_bottom_character(original));
1241                            copy_sub_list(accent_middle_character(copy), accent_middle_character(original));
1242                            break;
1243                    }
1244                    break;
1245                case fence_noad:
1246                    /* in principle also scripts */
1247                    copy_sub_node(fence_delimiter_list(copy), fence_delimiter_list(original));
1248                    copy_sub_node(fence_delimiter_top(copy), fence_delimiter_top(original));
1249                    copy_sub_node(fence_delimiter_bottom(copy), fence_delimiter_bottom(original));
1250                    break;
1251                case sub_box_node:
1252                case sub_mlist_node:
1253                    copy_sub_list(kernel_math_list(copy), kernel_math_list(original));
1254                    break;
1255                case par_node:
1256                    /* can also be copy_sub_node */
1257                    copy_sub_list(par_box_left(copy), par_box_left(original));
1258                    copy_sub_list(par_box_right(copy), par_box_right(original));
1259                    copy_sub_list(par_box_middle(copy), par_box_middle(original));
1260                    /* wipe copied fields */
1261                    par_left_skip(copy) = null;
1262                    par_right_skip(copy) = null;
1263                    par_par_fill_left_skip(copy) = null;
1264                    par_par_fill_right_skip(copy) = null;
1265                    par_par_init_left_skip(copy) = null;
1266                    par_par_init_right_skip(copy) = null;
1267                    par_emergency_left_skip(copy) = null;
1268                    par_emergency_right_skip(copy) = null;
1269                    par_baseline_skip(copy) = null;
1270                    par_line_skip(copy) = null;
1271                    par_par_shape(copy) = null;
1272                    par_inter_line_penalties(copy) = null;
1273                    par_club_penalties(copy) = null;
1274                    par_widow_penalties(copy) = null;
1275                    par_display_widow_penalties(copy) = null;
1276                    par_orphan_penalties(copy) = null;
1277                    par_par_passes(copy) = null;
1278                    /* really copy fields */
1279                    tex_set_par_par(copy, par_left_skip_code, tex_get_par_par(original, par_left_skip_code), 1);
1280                    tex_set_par_par(copy, par_right_skip_code, tex_get_par_par(original, par_right_skip_code), 1);
1281                    tex_set_par_par(copy, par_par_fill_left_skip_code, tex_get_par_par(original, par_par_fill_left_skip_code), 1);
1282                    tex_set_par_par(copy, par_par_fill_right_skip_code, tex_get_par_par(original, par_par_fill_right_skip_code), 1);
1283                    tex_set_par_par(copy, par_par_init_left_skip_code, tex_get_par_par(original, par_par_init_left_skip_code), 1);
1284                    tex_set_par_par(copy, par_par_init_right_skip_code, tex_get_par_par(original, par_par_init_right_skip_code), 1);
1285                    tex_set_par_par(copy, par_baseline_skip_code, tex_get_par_par(original, par_baseline_skip_code), 1);
1286                    tex_set_par_par(copy, par_line_skip_code, tex_get_par_par(original, par_line_skip_code), 1);
1287                    tex_set_par_par(copy, par_par_shape_code, tex_get_par_par(original, par_par_shape_code), 1);
1288                    tex_set_par_par(copy, par_inter_line_penalties_code, tex_get_par_par(original, par_inter_line_penalties_code), 1);
1289                    tex_set_par_par(copy, par_club_penalties_code, tex_get_par_par(original, par_club_penalties_code), 1);
1290                    tex_set_par_par(copy, par_widow_penalties_code, tex_get_par_par(original, par_widow_penalties_code), 1);
1291                    tex_set_par_par(copy, par_display_widow_penalties_code, tex_get_par_par(original, par_display_widow_penalties_code), 1);
1292                    tex_set_par_par(copy, par_orphan_penalties_code, tex_get_par_par(original, par_orphan_penalties_code), 1);
1293                    tex_set_par_par(copy, par_par_passes_code, tex_get_par_par(original, par_par_passes_code), 1);
1294                    /* tokens, we could mess with a ref count instead */
1295                    par_end_par_tokens(copy) = par_end_par_tokens(original);
1296                    tex_add_token_reference(par_end_par_tokens(original));
1297                    break;
1298                case specification_node:
1299                    tex_copy_specification_list(copy, original);
1300                    break;
1301                default:
1302                    break;
1303            }
1304        }
1305        return copy;
1306    }
1307}
1308
1309inline static void tex_aux_free_sub_node_list(halfword source)
1310{
1311    if (source) {
1312        tex_flush_node_list(source);
1313    }
1314}
1315
1316inline static void tex_aux_free_sub_node(halfword source)
1317{
1318    if (source) {
1319        tex_flush_node(source);
1320    }
1321}
1322
1323/* We don't need the checking for attributes if we make these lists frozen. */
1324
1325void tex_flush_node(halfword p)
1326{
1327    if (! p) {
1328        /*tex legal, but no-op. */
1329        return;
1330    } else if (p <= lmt_node_memory_state.reserved || p >= lmt_node_memory_state.nodes_data.allocated) {
1331        tex_formatted_error("nodes", "attempt to free an impossible node %d of type %d", (int) p, node_type(p));
1332    } else if (lmt_node_memory_state.nodesizes[p] == 0) {
1333        for (int i = (lmt_node_memory_state.reserved + 1); i < lmt_node_memory_state.nodes_data.allocated; i++) {
1334            if (lmt_node_memory_state.nodesizes[i] > 0) {
1335                tex_aux_check_node(i);
1336            }
1337        }
1338        tex_formatted_error("nodes", "attempt to double-free %s node %d, ignored", get_node_name(node_type(p)), (int) p);
1339    } else {
1340        int t = node_type(p);
1341        if (tex_nodetype_is_complex(t)) {
1342            switch (t) {
1343                case glue_node:
1344                    tex_aux_free_sub_node_list(glue_leader_ptr(p));
1345                    break;
1346                case hlist_node:
1347                    tex_aux_free_sub_node_list(box_pre_adjusted(p));
1348                    tex_aux_free_sub_node_list(box_post_adjusted(p));
1349                    // fall through
1350                case vlist_node:
1351                    tex_aux_free_sub_node_list(box_pre_migrated(p));
1352                    tex_aux_free_sub_node_list(box_post_migrated(p));
1353                    // fall through
1354                case unset_node:
1355                    tex_aux_free_sub_node_list(box_list(p));
1356                    break;
1357                case disc_node:
1358                    /*tex Watch the start at temp node hack! */
1359                    tex_aux_free_sub_node_list(disc_pre_break_head(p));
1360                    tex_aux_free_sub_node_list(disc_post_break_head(p));
1361                    tex_aux_free_sub_node_list(disc_no_break_head(p));
1362                    break;
1363                case par_node:
1364                    tex_aux_free_sub_node_list(par_box_left(p));
1365                    tex_aux_free_sub_node_list(par_box_right(p));
1366                    tex_aux_free_sub_node_list(par_box_middle(p));
1367                    /* we could check for the flag */
1368                    tex_flush_node(par_left_skip(p));
1369                    tex_flush_node(par_right_skip(p));
1370                    tex_flush_node(par_par_fill_left_skip(p));
1371                    tex_flush_node(par_par_fill_right_skip(p));
1372                    tex_flush_node(par_par_init_left_skip(p));
1373                    tex_flush_node(par_par_init_right_skip(p));
1374                    tex_flush_node(par_emergency_left_skip(p));
1375                    tex_flush_node(par_emergency_right_skip(p));
1376                    tex_flush_node(par_baseline_skip(p));
1377                    tex_flush_node(par_line_skip(p));
1378                    tex_flush_node(par_par_shape(p));
1379                    tex_flush_node(par_club_penalties(p));
1380                    tex_flush_node(par_inter_line_penalties(p));
1381                    tex_flush_node(par_widow_penalties(p));
1382                    tex_flush_node(par_display_widow_penalties(p));
1383                    tex_flush_node(par_orphan_penalties(p));
1384                    tex_flush_node(par_par_passes(p));
1385                    /* tokens */
1386                    tex_flush_token_list(par_end_par_tokens(p));
1387                    break;
1388                case insert_node:
1389                    tex_flush_node_list(insert_list(p));
1390                    break;
1391                case mark_node:
1392                    tex_delete_token_reference(mark_ptr(p));
1393                    break;
1394                case adjust_node:
1395                    tex_flush_node_list(adjust_list(p));
1396                    break;
1397                case choice_node:
1398                    tex_aux_free_sub_node_list(choice_display_mlist(p));
1399                    tex_aux_free_sub_node_list(choice_text_mlist(p));
1400                    tex_aux_free_sub_node_list(choice_script_mlist(p));
1401                    tex_aux_free_sub_node_list(choice_script_script_mlist(p));
1402                    break;
1403                case simple_noad:
1404                case fraction_noad:
1405                case radical_noad:
1406                case accent_noad:
1407                    tex_aux_free_sub_node_list(noad_nucleus(p));
1408                    tex_aux_free_sub_node_list(noad_subscr(p));
1409                    tex_aux_free_sub_node_list(noad_supscr(p));
1410                    tex_aux_free_sub_node_list(noad_subprescr(p));
1411                    tex_aux_free_sub_node_list(noad_supprescr(p));
1412                    tex_aux_free_sub_node_list(noad_prime(p));
1413                 // tex_aux_free_sub_node_list(noad_state(p));
1414                    switch (t) {
1415                        case fraction_noad:
1416                         // tex_aux_free_sub_node_list(fraction_numerator(p));
1417                         // tex_aux_free_sub_node_list(fraction_denominator(p));
1418                            tex_aux_free_sub_node(fraction_left_delimiter(p));
1419                            tex_aux_free_sub_node(fraction_right_delimiter(p));
1420                            tex_aux_free_sub_node(fraction_middle_delimiter(p));
1421                            break;
1422                        case radical_noad:
1423                            tex_aux_free_sub_node(radical_left_delimiter(p));
1424                            tex_aux_free_sub_node(radical_right_delimiter(p));
1425                            tex_aux_free_sub_node(radical_top_delimiter(p));
1426                            tex_aux_free_sub_node(radical_bottom_delimiter(p));
1427                            tex_aux_free_sub_node_list(radical_degree(p));
1428                            break;
1429                        case accent_noad:
1430                            tex_aux_free_sub_node_list(accent_top_character(p));
1431                            tex_aux_free_sub_node_list(accent_bottom_character(p));
1432                            tex_aux_free_sub_node_list(accent_middle_character(p));
1433                            break;
1434                    }
1435                    break;
1436                case fence_noad:
1437                    tex_aux_free_sub_node_list(fence_delimiter_list(p));
1438                    tex_aux_free_sub_node_list(fence_delimiter_top(p));
1439                    tex_aux_free_sub_node_list(fence_delimiter_bottom(p));
1440                    break;
1441                case sub_box_node:
1442                case sub_mlist_node:
1443                    tex_aux_free_sub_node_list(kernel_math_list(p));
1444                    break;
1445                case specification_node:
1446                    tex_dispose_specification_list(p);
1447                    break;
1448                default:
1449                    break;
1450            }
1451            if (tex_nodetype_has_attributes(t)) {
1452                delete_attribute_reference(node_attr(p));
1453                node_attr(p) = null; /* when we debug */
1454                lmt_properties_reset(lmt_lua_state.lua_instance, p);
1455            }
1456        }
1457        tex_free_node(p, get_node_size(t));
1458    }
1459}
1460
1461/*tex Erase the list of nodes starting at |pp|. */
1462
1463void tex_flush_node_list(halfword l)
1464{
1465    if (! l) {
1466        /*tex Legal, but no-op. */
1467        return;
1468    } else if (l <= lmt_node_memory_state.reserved || l >= lmt_node_memory_state.nodes_data.allocated) {
1469        tex_formatted_error("nodes", "attempt to free an impossible node list %d of type %d", (int) l, node_type(l));
1470    } else if (lmt_node_memory_state.nodesizes[l] == 0) {
1471        for (int i = (lmt_node_memory_state.reserved + 1); i < lmt_node_memory_state.nodes_data.allocated; i++) {
1472            if (lmt_node_memory_state.nodesizes[i] > 0) {
1473                tex_aux_check_node(i);
1474            }
1475        }
1476        tex_formatted_error("nodes", "attempt to double-free %s node %d, ignored", get_node_name(node_type(l)), (int) l);
1477    } else {
1478        /*tex Saves stack and time. */
1479        lua_State *L = lmt_lua_state.lua_instance;
1480        lmt_properties_push(L);
1481        while (l) {
1482            halfword nxt = node_next(l);
1483            tex_flush_node(l);
1484            l = nxt;
1485        }
1486        /*tex Saves stack and time. */
1487        lmt_properties_pop(L);
1488    }
1489}
1490
1491static void tex_aux_check_node(halfword p)
1492{
1493    halfword type = node_type(p);
1494    switch (type) {
1495        case glue_node:
1496            tex_aux_node_range_test(p, glue_leader_ptr(p));
1497            break;
1498        case hlist_node:
1499            tex_aux_node_range_test(p, box_pre_adjusted(p));
1500            tex_aux_node_range_test(p, box_post_adjusted(p));
1501            // fall through
1502        case vlist_node:
1503            tex_aux_node_range_test(p, box_pre_migrated(p));
1504            tex_aux_node_range_test(p, box_post_migrated(p));
1505            // fall through
1506        case unset_node:
1507        case align_record_node:
1508            tex_aux_node_range_test(p, box_list(p));
1509            break;
1510        case insert_node:
1511            tex_aux_node_range_test(p, insert_list(p));
1512            break;
1513        case disc_node:
1514            tex_aux_node_range_test(p, disc_pre_break_head(p));
1515            tex_aux_node_range_test(p, disc_post_break_head(p));
1516            tex_aux_node_range_test(p, disc_no_break_head(p));
1517            break;
1518        case adjust_node:
1519            tex_aux_node_range_test(p, adjust_list(p));
1520            break;
1521        case choice_node:
1522            tex_aux_node_range_test(p, choice_display_mlist(p));
1523            tex_aux_node_range_test(p, choice_text_mlist(p));
1524            tex_aux_node_range_test(p, choice_script_mlist(p));
1525            tex_aux_node_range_test(p, choice_script_script_mlist(p));
1526            break;
1527        case simple_noad:
1528        case radical_noad:
1529        case fraction_noad:
1530        case accent_noad:
1531            tex_aux_node_range_test(p, noad_nucleus(p));
1532            tex_aux_node_range_test(p, noad_subscr(p));
1533            tex_aux_node_range_test(p, noad_supscr(p));
1534            tex_aux_node_range_test(p, noad_subprescr(p));
1535            tex_aux_node_range_test(p, noad_supprescr(p));
1536            tex_aux_node_range_test(p, noad_prime(p));
1537         // tex_aux_node_range_test(p, noad_state(p));
1538            switch (type) {
1539                case radical_noad:
1540                    tex_aux_node_range_test(p, radical_degree(p));
1541                    tex_aux_node_range_test(p, radical_left_delimiter(p));
1542                    tex_aux_node_range_test(p, radical_right_delimiter(p));
1543                    tex_aux_node_range_test(p, radical_top_delimiter(p));
1544                    tex_aux_node_range_test(p, radical_bottom_delimiter(p));
1545                    break;
1546                case fraction_noad:
1547                 // tex_aux_node_range_test(p, fraction_numerator(p));
1548                 // tex_aux_node_range_test(p, fraction_denominator(p));
1549                    tex_aux_node_range_test(p, fraction_left_delimiter(p));
1550                    tex_aux_node_range_test(p, fraction_right_delimiter(p));
1551                    tex_aux_node_range_test(p, fraction_middle_delimiter(p));
1552                    break;
1553                case accent_noad:
1554                    tex_aux_node_range_test(p, accent_top_character(p));
1555                    tex_aux_node_range_test(p, accent_bottom_character(p));
1556                    tex_aux_node_range_test(p, accent_middle_character(p));
1557                    break;
1558            }
1559            break;
1560        case fence_noad:
1561            tex_aux_node_range_test(p, fence_delimiter_list(p));
1562            tex_aux_node_range_test(p, fence_delimiter_top(p));
1563            tex_aux_node_range_test(p, fence_delimiter_bottom(p));
1564            break;
1565        case par_node:
1566            tex_aux_node_range_test(p, par_box_left(p));
1567            tex_aux_node_range_test(p, par_box_right(p));
1568            tex_aux_node_range_test(p, par_box_middle(p));
1569            tex_aux_node_range_test(p, par_left_skip(p));
1570            tex_aux_node_range_test(p, par_right_skip(p));
1571            tex_aux_node_range_test(p, par_baseline_skip(p));
1572            tex_aux_node_range_test(p, par_line_skip(p));
1573            tex_aux_node_range_test(p, par_par_shape(p));
1574            tex_aux_node_range_test(p, par_club_penalties(p));
1575            tex_aux_node_range_test(p, par_inter_line_penalties(p));
1576            tex_aux_node_range_test(p, par_widow_penalties(p));
1577            tex_aux_node_range_test(p, par_display_widow_penalties(p));
1578            tex_aux_node_range_test(p, par_orphan_penalties(p));
1579            tex_aux_node_range_test(p, par_par_fill_left_skip(p));
1580            tex_aux_node_range_test(p, par_par_fill_right_skip(p));
1581            tex_aux_node_range_test(p, par_par_init_left_skip(p));
1582            tex_aux_node_range_test(p, par_par_init_right_skip(p));
1583            tex_aux_node_range_test(p, par_emergency_left_skip(p));
1584            tex_aux_node_range_test(p, par_emergency_right_skip(p));
1585            tex_aux_node_range_test(p, par_par_passes(p));
1586            break;
1587        default:
1588            break;
1589    }
1590}
1591
1592/*
1593halfword fix_node_list(halfword head)
1594{
1595    if (head) {
1596        halfword tail = head;
1597        halfword next = node_next(head);
1598        while (next) {
1599            node_prev(next) = tail;
1600            tail = next;
1601            next = node_next(tail);
1602        }
1603        return tail;
1604    } else {
1605        return null;
1606    }
1607}
1608*/
1609
1610halfword tex_get_node(int size)
1611{
1612    if (size < max_chain_size) { /*tex This test should not be needed! */
1613        halfword p = lmt_node_memory_state.free_chain[size];
1614        if (p) {
1615            lmt_node_memory_state.free_chain[size] = node_next(p);
1616            lmt_node_memory_state.nodesizes[p] = (char) size;
1617            node_next(p) = null;
1618            lmt_node_memory_state.nodes_data.ptr += size;
1619            return p;
1620        } else {
1621            return tex_aux_allocated_node(size);
1622        }
1623    } else {
1624        return tex_normal_error("nodes", "there is a problem in getting a node, case 1");
1625    }
1626}
1627
1628void tex_free_node(halfword p, int size) /* no need to pass size, we can get it here */
1629{
1630    if (p > lmt_node_memory_state.reserved && size < max_chain_size) {
1631        lmt_node_memory_state.nodesizes[p] = 0;
1632        node_next(p) = lmt_node_memory_state.free_chain[size];
1633        lmt_node_memory_state.free_chain[size] = p;
1634        lmt_node_memory_state.nodes_data.ptr -= size;
1635    } else {
1636        tex_formatted_error("nodes", "node number %d of type %d with size %d should not be freed", (int) p, node_type(p), size);
1637    }
1638}
1639
1640/*tex
1641
1642    At the start of the node memory area we reserve some special nodes, for instance frequently
1643    used glue specifications. We could as well just use new_glue here but for the moment we stick
1644    to the traditional approach. We can omit the zeroing because it's already done.
1645
1646*/
1647
1648static void tex_aux_initialize_glue(halfword n, scaled amount, scaled stretch, scaled shrink, halfword stretchorder, halfword shrinkorder)
1649{
1650 // memset((void *) (node_memory_state.nodes + n), 0, (sizeof(memoryword) * node_memory_state.nodesizes[glue_spec_node]));
1651    node_type(n) = glue_spec_node;
1652    glue_amount(n) = amount;
1653    glue_stretch(n) = stretch;
1654    glue_shrink(n) = shrink;
1655    glue_stretch_order(n) = stretchorder;
1656    glue_shrink_order(n) = shrinkorder;
1657}
1658
1659static void tex_aux_initialize_whatever_node(halfword n, quarterword type)
1660{
1661 // memset((void *) (node_memory_state.nodes + n), 0, (sizeof(memoryword) * node_memory_state.nodesizes[t]));
1662    node_type(n) = type;
1663}
1664
1665static void tex_aux_initialize_character(halfword n, halfword chr)
1666{
1667 // memset((void *) (node_memory_state.nodes + n), 0, (sizeof(memoryword) * node_memory_state.nodesizes[glyph_node]));
1668    node_type(n) = glyph_node;
1669    glyph_character(n) = chr;
1670}
1671# define reserved_node_slots 32
1672
1673void tex_initialize_node_mem()
1674{
1675    memoryword *nodes = NULL;
1676    char *sizes = NULL;
1677    int size = 0;
1678    if (lmt_main_state.run_state == initializing_state) {
1679        size = lmt_node_memory_state.nodes_data.minimum;
1680        lmt_node_memory_state.reserved = last_reserved;
1681        lmt_node_memory_state.nodes_data.top = last_reserved + 1;
1682        lmt_node_memory_state.nodes_data.allocated = size;
1683        lmt_node_memory_state.nodes_data.ptr = last_reserved;
1684    } else {
1685        size = lmt_node_memory_state.nodes_data.allocated;
1686        lmt_node_memory_state.nodes_data.initial = lmt_node_memory_state.nodes_data.ptr;
1687    }
1688    if (size >0) {
1689        nodes = aux_allocate_clear_array(sizeof(memoryword), size, reserved_node_slots);
1690        sizes = aux_allocate_clear_array(sizeof(char), size, reserved_node_slots);
1691    }
1692    if (nodes && sizes) {
1693        lmt_node_memory_state.nodes = nodes;
1694        lmt_node_memory_state.nodesizes = sizes;
1695    } else {
1696        tex_overflow_error("nodes", size);
1697    }
1698}
1699
1700void tex_initialize_nodes(void)
1701{
1702    if (lmt_main_state.run_state == initializing_state) {
1703        /*tex Initialize static glue specs. */
1704
1705        tex_aux_initialize_glue(zero_glue,     0,      0,     0,               0,              0);
1706        tex_aux_initialize_glue(fi_glue,       0,      0,     0,   fi_glue_order,              0); /* why not |unity| here */
1707        tex_aux_initialize_glue(fi_l_glue,     0,  unity,     0,  fil_glue_order,              0); /* |\[vh]fil|    */
1708        tex_aux_initialize_glue(fi_ll_glue,    0,  unity,     0, fill_glue_order,              0); /* |\[vh]fill|   */
1709        tex_aux_initialize_glue(fi_ss_glue,    0,  unity, unity,  fil_glue_order, fil_glue_order); /* |\[vh]ss|     */
1710        tex_aux_initialize_glue(fi_l_neg_glue, 0, -unity,     0,  fil_glue_order,              0); /* |\[vh]filneg| */
1711
1712        /*tex Initialize node list heads. */
1713
1714        tex_aux_initialize_whatever_node(page_insert_head,  temp_node); /* actually a split node */
1715        tex_aux_initialize_whatever_node(contribute_head,   temp_node);
1716        tex_aux_initialize_whatever_node(page_head,         temp_node);
1717        tex_aux_initialize_whatever_node(temp_head,         temp_node);
1718        tex_aux_initialize_whatever_node(hold_head,         temp_node);
1719        tex_aux_initialize_whatever_node(post_adjust_head,  temp_node);
1720        tex_aux_initialize_whatever_node(pre_adjust_head,   temp_node);
1721        tex_aux_initialize_whatever_node(post_migrate_head, temp_node);
1722        tex_aux_initialize_whatever_node(pre_migrate_head,  temp_node);
1723        tex_aux_initialize_whatever_node(align_head,        temp_node);
1724        tex_aux_initialize_whatever_node(active_head,       unhyphenated_node);
1725        tex_aux_initialize_whatever_node(end_span,          span_node);
1726
1727        tex_aux_initialize_character(begin_period, '.');
1728        tex_aux_initialize_character(end_period,   '.');
1729    }
1730}
1731
1732int tex_used_node_count(void)
1733{
1734    int used = 0;
1735    for  (int i = lmt_node_memory_state.nodes_data.top; i > lmt_node_memory_state.reserved; i--) {
1736        if (lmt_node_memory_state.nodesizes[i] > 0 && (node_type(i) <= max_node_type)) {
1737            ++used;
1738        }
1739    }
1740    return used;
1741}
1742int tex_free_node_count(void)
1743{
1744    int free = 0;
1745    for (int i = 1; i < max_chain_size; i++) {
1746        halfword p = lmt_node_memory_state.free_chain[i];
1747        while (p) {
1748            ++free;
1749            p = node_next(p);
1750        }
1751    }
1752    return free;
1753}
1754
1755void tex_dump_node_mem(dumpstream f)
1756{
1757    dump_int(f, lmt_node_memory_state.nodes_data.allocated);
1758    dump_int(f, lmt_node_memory_state.nodes_data.top);
1759    dump_things(f, lmt_node_memory_state.nodes[0], (size_t) lmt_node_memory_state.nodes_data.top + 1);
1760    dump_things(f, lmt_node_memory_state.nodesizes[0], lmt_node_memory_state.nodes_data.top);
1761    dump_things(f, lmt_node_memory_state.free_chain[0], max_chain_size);
1762    dump_int(f, lmt_node_memory_state.nodes_data.ptr);
1763    dump_int(f, lmt_node_memory_state.reserved);
1764}
1765
1766/*tex
1767    Node memory is (currently) also used for some stack related nodes. Using dedicated arrays instead
1768    makes sense but on the other hand this is the charm of \TEX. Variable nodes are no longer using
1769    the node pool so we don't need clever code to reclaim space. We have plenty anyway.
1770*/
1771
1772void tex_undump_node_mem(dumpstream f) // todo: check allocation
1773{
1774    undump_int(f, lmt_node_memory_state.nodes_data.allocated);
1775    undump_int(f, lmt_node_memory_state.nodes_data.top);
1776    tex_initialize_node_mem();
1777    undump_things(f, lmt_node_memory_state.nodes[0], (size_t) lmt_node_memory_state.nodes_data.top + 1);
1778    undump_things(f, lmt_node_memory_state.nodesizes[0], (size_t) lmt_node_memory_state.nodes_data.top);
1779    undump_things(f, lmt_node_memory_state.free_chain[0], max_chain_size);
1780    undump_int(f, lmt_node_memory_state.nodes_data.ptr);
1781    undump_int(f, lmt_node_memory_state.reserved);
1782}
1783
1784static halfword tex_aux_allocated_node(int s)
1785{
1786    int old = lmt_node_memory_state.nodes_data.top;
1787    int new = old + s;
1788    if (new > lmt_node_memory_state.nodes_data.allocated) {
1789        if (lmt_node_memory_state.nodes_data.allocated + lmt_node_memory_state.nodes_data.step <= lmt_node_memory_state.nodes_data.size) {
1790            memoryword *nodes = aux_reallocate_array(lmt_node_memory_state.nodes, sizeof(memoryword), lmt_node_memory_state.nodes_data.allocated + lmt_node_memory_state.nodes_data.step, reserved_node_slots);
1791            char *sizes = aux_reallocate_array(lmt_node_memory_state.nodesizes, sizeof(char), lmt_node_memory_state.nodes_data.allocated + lmt_node_memory_state.nodes_data.step, reserved_node_slots);
1792            if (nodes && sizes) {
1793                lmt_node_memory_state.nodes = nodes;
1794                lmt_node_memory_state.nodesizes = sizes;
1795                memset((void *) (nodes + lmt_node_memory_state.nodes_data.allocated), 0, (size_t) lmt_node_memory_state.nodes_data.step * sizeof(memoryword));
1796                memset((void *) (sizes + lmt_node_memory_state.nodes_data.allocated), 0, (size_t) lmt_node_memory_state.nodes_data.step * sizeof(char));
1797                lmt_node_memory_state.nodes_data.allocated += lmt_node_memory_state.nodes_data.step;
1798                lmt_run_memory_callback("node", 1);
1799            } else {
1800                lmt_run_memory_callback("node", 0);
1801                tex_overflow_error("node memory size", lmt_node_memory_state.nodes_data.size);
1802            }
1803        }
1804        if (new > lmt_node_memory_state.nodes_data.allocated) {
1805            tex_overflow_error("node memory size", lmt_node_memory_state.nodes_data.size);
1806        }
1807    }
1808    /* We allocate way larger than the maximum size. */
1809 // printf("old=%i  size=%i  new=%i\n",old,s,new);
1810    lmt_node_memory_state.nodesizes[old] = (char) s;
1811    lmt_node_memory_state.nodes_data.top = new;
1812    return old;
1813}
1814
1815int tex_n_of_used_nodes(int counts[])
1816{
1817    int n = 0;
1818    for (int i = 0; i < max_node_type; i++) {
1819        counts[i] = 0;
1820    }
1821    for (int i = lmt_node_memory_state.nodes_data.top; i > lmt_node_memory_state.reserved; i--) {
1822        if (lmt_node_memory_state.nodesizes[i] > 0 && (node_type(i) <= max_node_type)) {
1823            counts[node_type(i)] += 1;
1824//printf("%i %i\n",node_type(i),node_subtype(i));
1825        }
1826    }
1827    for (int i = 0; i < max_node_type; i++) {
1828        n += counts[i];
1829    }
1830    return n;
1831}
1832
1833/* needs checking as we take from the pool */
1834
1835halfword tex_list_node_mem_usage(void)
1836{
1837    char *saved_varmem_sizes = aux_allocate_array(sizeof(char), lmt_node_memory_state.nodes_data.allocated, 1);
1838    if (saved_varmem_sizes) {
1839        halfword q = null;
1840        halfword p = null;
1841        memcpy(saved_varmem_sizes, lmt_node_memory_state.nodesizes, (size_t) lmt_node_memory_state.nodes_data.allocated);
1842        for (halfword i = lmt_node_memory_state.reserved + 1; i < (lmt_node_memory_state.nodes_data.allocated - 1); i++) {
1843            if (saved_varmem_sizes[i] > 0) {
1844                halfword j = tex_copy_node(i);
1845                if (p) {
1846                    node_next(p) = j;
1847                } else {
1848                    q = j;
1849                }
1850                p = j;
1851            }
1852        }
1853        aux_deallocate_array(saved_varmem_sizes);
1854        return q;
1855    } else {
1856        return null;
1857    }
1858}
1859
1860/*
1861    Now comes some attribute stuff. We could have a fast allocator for them and a dedicated pool
1862    (actually for each node type I guess).
1863*/
1864
1865extern void tex_change_attribute_register(halfword a, halfword id, halfword value)
1866{
1867    if (eq_value(id) != value) { 
1868        if (is_global(a)) { 
1869         // for (int i = (lmt_save_state.save_stack_data.ptr - 1); i >= 0; i--) { 
1870         //     if (save_type(i) == level_boundary_save_type) { 
1871         //         delete_attribute_reference(save_value_2(i)); /* watch the _2 here */
1872         //         save_value_2(i) = attribute_cache_disabled;  /* watch the _2 here */
1873         //     } 
1874         // } 
1875            int ptr = lmt_save_state.save_stack_data.ptr - 1; 
1876            while (ptr >= 0) { 
1877                if (save_type(ptr) == level_boundary_save_type) { 
1878                    delete_attribute_reference(save_value_2(ptr)); /* watch the _2 here */
1879                    save_value_2(ptr) = attribute_cache_disabled;  /* watch the _2 here */
1880                    if (ptr) { 
1881                        ptr = save_value(ptr);
1882                    } else {
1883                        break;
1884                    }
1885                } else { 
1886                    /* something is wrong here */
1887                    break;
1888                }
1889            }
1890        } else { 
1891            delete_attribute_reference(current_attribute_state); 
1892        } 
1893        set_current_attribute_state(attribute_cache_disabled); 
1894    } 
1895}
1896
1897inline static halfword tex_aux_new_attribute_list_node(halfword count)
1898{
1899    halfword r = tex_get_node(attribute_node_size);
1900    node_type(r) = attribute_node;
1901    node_subtype(r) = attribute_list_subtype;
1902    attribute_unset(r) = 0;
1903    attribute_count(r) = count;
1904    return r;
1905}
1906
1907inline static halfword tex_aux_new_attribute_node(halfword index, int value)
1908{
1909    halfword r = tex_get_node(attribute_node_size);
1910    node_type(r) = attribute_node;
1911    node_subtype(r) = attribute_value_subtype;
1912    attribute_index(r) = index;
1913    attribute_value(r) = value;
1914    return r;
1915}
1916
1917inline static halfword tex_aux_copy_attribute_node(halfword n)
1918{
1919    halfword a = tex_get_node(attribute_node_size);
1920    memcpy((void *) (lmt_node_memory_state.nodes + a), (void *) (lmt_node_memory_state.nodes + n), (sizeof(memoryword) * attribute_node_size));
1921    return a;
1922}
1923
1924halfword tex_copy_attribute_list(halfword a_old)
1925{
1926    if (a_old && a_old != attribute_cache_disabled) {
1927        halfword a_new = tex_aux_new_attribute_list_node(0);
1928        halfword p_old = a_old;
1929        halfword p_new = a_new;
1930        p_old = node_next(p_old);
1931        while (p_old) {
1932            halfword a = tex_copy_node(p_old);
1933            node_next(p_new) = a;
1934            p_new = a;
1935            p_old = node_next(p_old);
1936        }
1937        node_next(p_new) = null;
1938        return a_new;
1939    } else {
1940        return a_old;
1941    }
1942}
1943
1944halfword tex_copy_attribute_list_set(halfword a_old, int index, int value)
1945{
1946    halfword a_new = tex_aux_new_attribute_list_node(0);
1947    halfword p_new = a_new;
1948    int done = 0;
1949    if (a_old && a_old != attribute_cache_disabled) {
1950        halfword p_old = node_next(a_old);
1951        while (p_old) {
1952            halfword i = attribute_index(p_old);
1953            if (! done && i >= index) {
1954                if (value != unused_attribute_value) {
1955                    halfword a = tex_aux_new_attribute_node(index, value);
1956                    node_next(p_new) = a;
1957                    p_new = a;
1958                }
1959                done = 1;
1960                if (i == index) {
1961                    goto CONTINUE;
1962                }
1963            }
1964       /* APPEND: */
1965            {
1966                halfword a = tex_aux_copy_attribute_node(p_old);
1967                node_next(p_new) = a;
1968                p_new = a;
1969            }
1970          CONTINUE:
1971            p_old = node_next(p_old);
1972        }
1973        node_next(p_new) = null;
1974    }
1975    if (! done && value != unused_attribute_value) {
1976        halfword b = tex_aux_new_attribute_node(index, value);
1977        node_next(p_new) = b;
1978    }
1979    return a_new;
1980}
1981
1982static void tex_aux_update_attribute_cache(void)
1983{
1984    halfword p = tex_aux_new_attribute_list_node(0);
1985    set_current_attribute_state(p);
1986    for (int i = 0; i <= lmt_node_memory_state.max_used_attribute; i++) {
1987        int v = attribute_register(i);
1988        if (v > unused_attribute_value) {
1989            halfword r = tex_aux_new_attribute_node(i, v);
1990            node_next(p) = r;
1991            p = r;
1992        }
1993    }
1994    if (! node_next(current_attribute_state)) {
1995        tex_free_node(current_attribute_state, attribute_node_size);
1996        set_current_attribute_state(null);
1997    } else {
1998        add_attribute_reference(current_attribute_state);
1999    }
2000}
2001
2002void tex_build_attribute_list(halfword target)
2003{
2004    if (lmt_node_memory_state.max_used_attribute >= 0) {
2005        if (! current_attribute_state || current_attribute_state == attribute_cache_disabled) {
2006            tex_aux_update_attribute_cache();
2007            if (! current_attribute_state) {
2008                return;
2009            }
2010        }
2011        add_attribute_reference(current_attribute_state);
2012        /*tex Checking for validity happens before the call; the subtype can be unset (yet). */
2013        node_attr(target) = current_attribute_state;
2014    }
2015}
2016
2017halfword tex_current_attribute_list(void)
2018{
2019    if (lmt_node_memory_state.max_used_attribute >= 0) {
2020        if (! current_attribute_state || current_attribute_state == attribute_cache_disabled) {
2021            tex_aux_update_attribute_cache();
2022        }
2023        return current_attribute_state;
2024    } else {
2025        return null;
2026    }
2027}
2028
2029/*tex
2030
2031    There can be some gain in setting |attr_last_unset_enabled| but only when a lot of unsetting
2032    happens with rather long attribute lists, which actually is rare.
2033
2034    One tricky aspect if attributes is that when we test for a list head being the same, we have
2035    the problem that freeing and (re)allocating can result in the same node address. Flushing in
2036    reverse order sort of prevents that.
2037
2038*/
2039
2040void tex_dereference_attribute_list(halfword a)
2041{
2042    if (a && a != attribute_cache_disabled) {
2043        if (node_type(a) == attribute_node && node_subtype(a) == attribute_list_subtype){
2044            if (attribute_count(a) > 0) {
2045                --attribute_count(a);
2046                if (attribute_count(a) == 0) {
2047                    if (a == current_attribute_state) {
2048                        set_current_attribute_state(attribute_cache_disabled);
2049                    }
2050                    {
2051                        int u = 0;
2052                        /* this works (different order) */
2053if (0) { /* chains are often short */
2054                        while (a) {
2055                            halfword n = node_next(a);
2056                            lmt_node_memory_state.nodesizes[a] = 0;
2057                            node_next(a) = lmt_node_memory_state.free_chain[attribute_node_size];
2058                            lmt_node_memory_state.free_chain[attribute_node_size] = a;
2059                            ++u;
2060                            a = n;
2061                        }
2062} else { 
2063                        /* this doesn't always (which is weird) */
2064                        halfword h = a;
2065                        halfword t = a;
2066                        while (a) {
2067                            lmt_node_memory_state.nodesizes[a] = 0;
2068                            ++u;
2069                            t = a;
2070                            a = node_next(a);
2071                        }
2072                        node_next(t) = lmt_node_memory_state.free_chain[attribute_node_size];
2073                        lmt_node_memory_state.free_chain[attribute_node_size] = h;
2074}
2075                        /* */
2076                        lmt_node_memory_state.nodes_data.ptr -= u * attribute_node_size;
2077                    }
2078                }
2079            } else {
2080                tex_formatted_error("nodes", "zero referenced attribute list %i", a);
2081            }
2082        } else {
2083            tex_formatted_error("nodes", "trying to delete an attribute reference of a non attribute list node %i (%i)", a, node_type(a));
2084        }
2085    }
2086}
2087
2088/*tex
2089    Here |p| is an attr list head, or zero. This one works on a copy, so we can overwrite a value!
2090*/
2091
2092halfword tex_patch_attribute_list(halfword list, int index, int value)
2093{
2094    if (list == attribute_cache_disabled) {
2095        return list;
2096    } else if (list) {
2097        halfword current = node_next(list);
2098        halfword previous = list;
2099        while (current) {
2100            int i = attribute_index(current);
2101            if (i == index) {
2102                /*tex Replace: */
2103                attribute_value(current) = value;
2104                return list;
2105            } else if (i > index) {
2106                /*tex Prepend: */
2107                halfword r = tex_aux_new_attribute_node(index, value);
2108                node_next(previous) = r;
2109                node_next(r) = current;
2110                return list;
2111            } else {
2112                previous = current;
2113                current = node_next(current);
2114            }
2115        }
2116        {
2117            /*tex Append: */
2118            halfword r = tex_aux_new_attribute_node(index, value);
2119            node_next(r) = node_next(previous);
2120            node_next(previous) = r;
2121        }
2122    } else {
2123        /*tex Watch out, we don't set a ref count, this branch is not seen anyway. */
2124        halfword r = tex_aux_new_attribute_node(index, value);
2125        list = tex_aux_new_attribute_list_node(0);
2126        node_next(list) = r;
2127    }
2128    return list;
2129}
2130
2131/* todo: combine set and unset */
2132
2133void tex_set_attribute(halfword target, int index, int value)
2134{
2135    /*tex Not all nodes can have an attribute list. */
2136    if (tex_nodetype_has_attributes(node_type(target))) {
2137        if (value == unused_attribute_value) {
2138            tex_unset_attribute(target, index, value);
2139        } else {
2140            /*tex If we have no list, we create one and quit. */
2141            halfword a = node_attr(target);
2142            /* needs checking: can we get an empty one here indeed, the vlink test case ... */
2143            if (a) {
2144                halfword p = node_next(a);
2145                while (p) {
2146                    int i = attribute_index(p);
2147                    if (i == index) {
2148                        if (attribute_value(p) == value) {
2149                            return;
2150                        } else {
2151                            break;
2152                        }
2153                    } else if (i > index) {
2154                        break;
2155                    } else {
2156                        p = node_next(p);
2157                    }
2158                }
2159         //     p = tex_copy_attribute_list_set(a, index, value);
2160         //     tex_attach_attribute_list_attribute(target, p);
2161         // } else {
2162         //     halfword p = tex_copy_attribute_list_set(null, index, value);
2163         //     tex_attach_attribute_list_attribute(target, p);
2164         // }
2165            }
2166            a = tex_copy_attribute_list_set(a, index, value);
2167            tex_attach_attribute_list_attribute(target, a);
2168        }
2169    }
2170}
2171
2172int tex_unset_attribute(halfword target, int index, int value)
2173{
2174    if (tex_nodetype_has_attributes(node_type(target))) {
2175        halfword p = node_attr(target);
2176        if (p) {
2177            halfword c = node_next(p);
2178            while (c) {
2179                halfword i = attribute_index(c);
2180                if (i == index) {
2181                    halfword v = attribute_value(c);
2182                    if (v != value) {
2183                        halfword l = tex_copy_attribute_list_set(p, index, value);
2184                        tex_attach_attribute_list_attribute(target, l);
2185                    }
2186                    return v;
2187                } else if (i > index) {
2188                    return unused_attribute_value;
2189                }
2190                c = node_next(c);
2191            }
2192        }
2193    }
2194    return unused_attribute_value;
2195}
2196
2197void tex_unset_attributes(halfword first, halfword last, int index)
2198{
2199    halfword a = null;
2200    halfword q = null;
2201    halfword n = first;
2202    while (n) {
2203        if (tex_nodetype_has_attributes(node_type(n))) {
2204            halfword p = node_attr(n);
2205            if (p) {
2206                if (p == q) {
2207                    tex_attach_attribute_list_attribute(n, a);
2208                } else {
2209                    halfword c = node_next(p);
2210                    while (c) {
2211                        halfword i = attribute_index(c);
2212                        if (i == index) {
2213                            q = p;
2214                            a = tex_copy_attribute_list_set(p, index, unused_attribute_value); /* check */
2215                            tex_attach_attribute_list_attribute(n, a);
2216                            break;
2217                        } else if (i > index) {
2218                            break;
2219                        }
2220                        c = node_next(c);
2221                    }
2222                }
2223            }
2224        }
2225        if (n == last) {
2226            break;
2227        } else {
2228            n = node_next(n);
2229        }
2230    }
2231}
2232
2233int tex_has_attribute(halfword n, int index, int value)
2234{
2235    if (tex_nodetype_has_attributes(node_type(n))) {
2236        halfword p = node_attr(n);
2237        if (p) {
2238            p = node_next(p);
2239            while (p) {
2240                if (attribute_index(p) == index) {
2241                    int v = attribute_value(p);
2242                    if (value == v || value == unused_attribute_value) {
2243                        return v;
2244                    } else {
2245                        return unused_attribute_value;
2246                    }
2247                } else if (attribute_index(p) > index) {
2248                    return unused_attribute_value;
2249                }
2250                p = node_next(p);
2251            }
2252        }
2253    }
2254    return unused_attribute_value;
2255}
2256
2257/*tex
2258    Because we have more detail available we provide node names and show a space when we have one.
2259    The disc nodes are also more granular. I might drop the font in showing glyph nodes. A previous
2260    version used full node types inside brackets but we now collapse the node types and use only
2261    the first character of the type. Eventually I might come up with some variants.
2262 */
2263
2264void tex_print_short_node_contents(halfword p)
2265{
2266    int collapsing = 0;
2267    while (p) {
2268        switch (node_type(p)) {
2269            case rule_node:
2270                if (collapsing) { tex_print_char(']'); collapsing = 0; }
2271                tex_print_char('|');
2272                break;
2273            case glue_node:
2274                switch (node_subtype(p)) {
2275                    case space_skip_glue:
2276                    case xspace_skip_glue:
2277                    case zero_space_skip_glue:
2278                        if (collapsing) { tex_print_char(']'); collapsing = 0; }
2279                        tex_print_char(' ');
2280                        break;
2281                    default:
2282                        goto DEFAULT;
2283                }
2284                break;
2285            case math_node:
2286                if (collapsing) { tex_print_char(']'); collapsing = 0; }
2287                tex_print_char('$');
2288                break;
2289            case disc_node:
2290                if (collapsing) { tex_print_char(']'); collapsing = 0; }
2291                tex_print_str("[[");
2292                tex_print_short_node_contents(disc_pre_break_head(p));
2293                tex_print_str("][");
2294                tex_print_short_node_contents(disc_post_break_head(p));
2295                tex_print_str("][");
2296                tex_print_short_node_contents(disc_no_break_head(p));
2297                tex_print_str("]]");
2298                break;
2299            case dir_node:
2300                if (collapsing) { tex_print_char(']'); collapsing = 0; }
2301                if (node_subtype(p) == cancel_dir_subtype) {
2302                    tex_print_str(" >");
2303                } else {
2304                    tex_print_str(dir_direction(p) ? "<r2l " : "<l2r ");
2305                }
2306                break;
2307            case glyph_node:
2308                if (collapsing) { tex_print_char(']'); collapsing = 0; }
2309                if (glyph_font(p) != lmt_print_state.font_in_short_display) {
2310                    tex_print_font_identifier(glyph_font(p));
2311                    tex_print_char(' ');
2312                    lmt_print_state.font_in_short_display = glyph_font(p);
2313                }
2314                tex_print_tex_str(glyph_character(p));
2315                break;
2316            case par_node:
2317                if (collapsing) { tex_print_char(']'); collapsing = 0; }
2318                tex_print_str(par_dir(p) ? "<r2l p>" : "<l2r p>");
2319                break;
2320            default:
2321              DEFAULT:
2322                if (! collapsing) {
2323                    tex_print_char('[');
2324                    collapsing = 1;
2325                }
2326                tex_print_char(lmt_interface.node_data[node_type(p)].name[0]);
2327                break;
2328        }
2329        p = node_next(p);
2330    }
2331    if (collapsing) {
2332        tex_print_char(']');
2333    }
2334}
2335
2336/*tex
2337
2338    Now we are ready for |show_node_list| itself. This procedure has been written to be \quote
2339    {extra robust} in the sense that it should not crash or get into a loop even if the data
2340    structures have been messed up by bugs in the rest of the program. You can safely call its
2341    parent routine |show_box(p)| for arbitrary values of |p| when you are debugging \TEX. However,
2342    in the presence of bad data, the procedure may fetch a |memoryword| whose variant is different
2343    from the way it was stored; for example, it might try to read |mem[p].hh| when |mem[p]|
2344    contains a scaled integer, if |p| is a pointer that has been clobbered or chosen at random.
2345
2346*/
2347
2348void tex_print_node_list(halfword p, const char *what, int threshold, int max)
2349{
2350    if (p) {
2351        if (what) {
2352            tex_append_char('.');
2353            tex_append_char('.');
2354            tex_print_levels();
2355            tex_print_current_string();
2356            tex_print_str_esc(what);
2357        } else {
2358            /*tex This happens in math. */
2359        }
2360        tex_append_char('.');
2361        tex_append_char('.');
2362        tex_show_node_list(p, threshold, max); // show_box_depth_par, show_box_breadth_par
2363        tex_flush_char();
2364        tex_flush_char();
2365        if (what) {
2366            tex_flush_char();
2367            tex_flush_char();
2368        }
2369    }
2370}
2371
2372/*tex
2373
2374    Print a node list symbolically. This one is adaped to the fact that we have a bit more
2375    granularity in subtypes and some more fields. It is therefore not compatible with traditional
2376    \TEX. This is work in progress. I will also normalize some subtype names so ...
2377
2378*/
2379
2380static void tex_aux_show_attr_list(halfword p)
2381{
2382     p = node_attr(p);
2383     if (p) {
2384        int callback_id = lmt_callback_defined(get_attribute_callback);
2385        if (tracing_nodes_par > 1) {
2386            tex_print_format("<%i#%i>", p, attribute_count(p));
2387        }
2388        tex_print_char('[');
2389        p = node_next(p);
2390        while (p) {
2391            halfword k = attribute_index(p);
2392            halfword v = attribute_value(p);
2393            if (callback_id) {
2394                strnumber u = tex_save_cur_string();
2395                char *ks = NULL;
2396                char *vs = NULL;
2397                lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "dd->RR", k, v, &ks, &vs);
2398                tex_restore_cur_string(u);
2399                if (ks) {
2400                    tex_print_str(ks);
2401                    lmt_memory_free(ks);
2402                } else {
2403                    tex_print_int(k);
2404                }
2405                tex_print_char('=');
2406                if (vs) {
2407                    tex_print_str(vs);
2408                    lmt_memory_free(vs);
2409                } else {
2410                    tex_print_int(v);
2411                }
2412            } else {
2413                tex_print_format("%i=%i", k, v);
2414            };
2415            p = node_next(p);
2416            if (p) {
2417                tex_print_char(',');
2418            }
2419        }
2420        tex_print_char(']');
2421    }
2422}
2423
2424void tex_print_name(halfword n, const char* what)
2425{
2426    tex_print_str_esc(what);
2427    if (tracing_nodes_par > 0) {
2428        tex_print_format("<%i>", n);
2429    }
2430}
2431
2432static void tex_aux_print_subtype_and_attributes_str(halfword p, const char *n)
2433{
2434    if (show_node_details_par > 0) {
2435        tex_print_format("[%s]",n);
2436    }
2437    if (show_node_details_par > 1 && tex_nodetype_has_attributes(node_type(p))) {
2438        tex_aux_show_attr_list(p);
2439    }
2440}
2441
2442void tex_print_extended_subtype(halfword p, quarterword s)
2443{
2444    halfword st = s;
2445    switch (p ? node_type(p) : simple_noad) {
2446        case hlist_node:
2447            if (s > noad_class_list_base) {
2448                st -= noad_class_list_base;
2449            }
2450        case simple_noad:
2451        case math_char_node:
2452            {
2453                int callback_id = lmt_callback_defined(get_noad_class_callback);
2454                if (callback_id) {
2455                    strnumber u = tex_save_cur_string();
2456                    char *v = NULL;
2457                    lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "d->R", st, &v);
2458                    tex_restore_cur_string(u);
2459                    if (v) {
2460                        if (p && node_type(p) == hlist_node) {
2461                            tex_print_str("math");
2462                        }
2463                        tex_print_str(v);
2464                        lmt_memory_free(v);
2465                        break;
2466                    }
2467                }
2468                /* fall through */
2469            }
2470            break;
2471        default:
2472            tex_print_int(s);
2473            break;
2474    }
2475}
2476
2477static void tex_print_subtype_and_attributes_info(halfword p, quarterword s, node_info *data)
2478{
2479    if (show_node_details_par > 0) {
2480        tex_print_char('[');
2481        if (data && data->subtypes && s >= data->first && s <= data->last) {
2482            tex_print_str(data->subtypes[s].name);
2483        } else {
2484            tex_print_extended_subtype(p, s);
2485        }
2486        tex_print_char(']');
2487    }
2488    if (show_node_details_par > 1 && tex_nodetype_has_attributes(node_type(p))) {
2489        tex_aux_show_attr_list(p);
2490    }
2491}
2492
2493static void tex_print_node_and_details(halfword p)
2494{
2495    halfword type = node_type(p);
2496    quarterword subtype = node_subtype(p);
2497    tex_print_name(p, lmt_interface.node_data[type].name);
2498    switch (type) {
2499        case temp_node:
2500        case whatsit_node:
2501            return;
2502    }
2503    tex_print_subtype_and_attributes_info(p, subtype, &lmt_interface.node_data[type]);
2504}
2505
2506static void tex_aux_print_subtype_and_attributes_int(halfword p, halfword n)
2507{
2508    if (show_node_details_par > 0) { \
2509        tex_print_format("[%i]", n);
2510    }
2511    if (show_node_details_par > 1 && tex_nodetype_has_attributes(node_type(p))) {
2512        tex_aux_show_attr_list(p);
2513    }
2514}
2515
2516const char *tex_aux_subtype_str(halfword n)
2517{
2518    if (n) {
2519        node_info *data = &lmt_interface.node_data[node_type(n)];
2520        if (data && data->subtypes && node_subtype(n) >= data->first && node_subtype(n) <= data->last) {
2521            return data->subtypes[node_subtype(n)].name;
2522        }
2523    }
2524    return "";
2525}
2526
2527/*tex
2528
2529    We're not downward compatible here and it might even evolve a bit (and maybe I'll add a
2530    compability mode too). We have way more information and plenty of log space so there is no
2531    need to be compact. Consider it work in progress.
2532
2533    I admit that there is some self interest here in adding more detail. At some point (around
2534    ctx 2019) I needed to see attribute values in the trace so I added that option which in turn
2535    made me reformat the output a bit. Of course it makes sense to have the whole show be a
2536    callback (and I might actually do that) but on the other hand it's so integral to \TEX\ that
2537    it doesn't add much and in all the years that \LUATEX| is now arround I never really needed
2538    it anyway.
2539
2540    One option is to go completely |\node[key=value,key={value,value}]| here as that can be easily
2541    parsed. It's to be decided.
2542
2543    What is the string pool char data used for here?
2544
2545    Per version 2.09.22 we use the values from the node definitions which is more consistent and
2546    also makes the binary somewhat smaller. It's all in the details. It's a typical example of
2547    a change doen when we're stabel for a while (as it influences tracing).
2548
2549*/
2550
2551static void tex_print_specnode(halfword v, int unit) /* for now local */
2552{
2553    if (tracing_nodes_par > 2) {
2554        tex_print_format("<%i>", v);
2555    }
2556    tex_print_spec(v, unit); 
2557}
2558
2559void tex_aux_show_dictionary(halfword p, halfword properties, halfword group, halfword index,halfword font, halfword character)
2560{
2561    int callback_id = lmt_callback_defined(get_math_dictionary_callback);
2562    if (callback_id) {
2563        strnumber u = tex_save_cur_string();
2564        char *s = NULL;
2565        lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "Nddddd->R", p, properties, group, index, font, character, &s);
2566        tex_restore_cur_string(u);
2567        if (s) {
2568            tex_print_format(", %s", s);
2569            lmt_memory_free(s);
2570            return;
2571        }
2572    }
2573    if (properties) {
2574        tex_print_format(", properties %x", properties);
2575    }
2576    if (group) {
2577        tex_print_format(", group %x", group);
2578    }
2579    if (index) {
2580        tex_print_format(", index %x", index);
2581    }
2582}
2583
2584void tex_show_node_list(halfword p, int threshold, int max)
2585{
2586    if ((int) lmt_string_pool_state.string_temp_top > threshold) {
2587        if (p > null) {
2588            /*tex Indicate that there's been some truncation. */
2589            tex_print_format("[tracing depth %i reached]", threshold);
2590        }
2591        return;
2592    } else {
2593        /*tex The number of items already printed at this level: */
2594        int n = 0;
2595        if (max <= 0) { 
2596            max = 5;
2597        }
2598        while (p) {
2599            tex_print_levels();
2600            tex_print_current_string();
2601            ++n;
2602            if (n > max) {
2603                /*tex Time to stop. */
2604                halfword t = tex_tail_of_node_list(p);
2605                if (t == p) {
2606                    /*tex We've showed the whole list. */
2607                    return;
2608                } else if (p == node_prev(t)) {
2609                 // /*tex We're just before the end. */
2610                } else {
2611                    tex_print_format("[tracing breadth %i reached]", max);
2612                    return;
2613                }
2614            }
2615            tex_print_node_and_details(p);
2616            switch (node_type(p)) {
2617                case glyph_node:
2618                    if (show_node_details_par > 0) {
2619                        scaledwhd whd = tex_char_whd_from_glyph(p);
2620                        if (glyph_protected(p)) {
2621                            tex_print_str(", protected");
2622                        }
2623                        /* effective */
2624                        if (whd.wd) {
2625                            tex_print_format(", wd %p", whd.wd);
2626                        }
2627                        if (whd.ht) {
2628                            tex_print_format(", ht %p", whd.ht);
2629                        }
2630                        if (whd.dp) {
2631                            tex_print_format(", dp %p", whd.dp);
2632                        }
2633                        if (whd.ic) {
2634                            tex_print_format(", ic %p", whd.ic);
2635                        }
2636                        /* */
2637                        if (get_glyph_language(p)) {
2638                            tex_print_format(", language (n=%i,l=%i,r=%i)", get_glyph_language(p), get_glyph_lhmin(p), get_glyph_rhmin(p));
2639                        }
2640                        if (get_glyph_script(p)) {
2641                            tex_print_format(", script %i", get_glyph_script(p));
2642                        }
2643                        if (get_glyph_hyphenate(p)) {
2644                            tex_print_format(", hyphenationmode %x", get_glyph_hyphenate(p));
2645                        }
2646                        if (glyph_x_offset(p)) {
2647                            tex_print_format(", xoffset %p", glyph_x_offset(p));
2648                        }
2649                        if (glyph_y_offset(p)) {
2650                            tex_print_format(", yoffset %p", glyph_y_offset(p));
2651                        }
2652                        if (glyph_left(p)) {
2653                            tex_print_format(", left %p", glyph_left(p));
2654                        }
2655                        if (glyph_right(p)) {
2656                            tex_print_format(", right %p", glyph_right(p));
2657                        }
2658                        if (glyph_raise(p)) {
2659                            tex_print_format(", raise %p", glyph_raise(p));
2660                        }
2661                        if (glyph_expansion(p)) {
2662                            tex_print_format(", expansion %i", glyph_expansion(p));
2663                        }
2664                        if (glyph_scale(p) && glyph_scale(p) != scaling_factor) {
2665                            tex_print_format(", scale %i", glyph_scale(p));
2666                        }
2667                        if (glyph_x_scale(p) && glyph_x_scale(p) != scaling_factor) {
2668                            tex_print_format(", xscale %i", glyph_x_scale(p));
2669                        }
2670                        if (glyph_y_scale(p) && glyph_y_scale(p) != scaling_factor) {
2671                            tex_print_format(", yscale %i", glyph_y_scale(p));
2672                        }
2673                        if (glyph_data(p)) {
2674                            tex_print_format(", data %i", glyph_data(p));
2675                        }
2676                        if (glyph_state(p)) {
2677                            tex_print_format(", state %i", glyph_state(p));
2678                        }
2679                        if (glyph_options(p)) {
2680                            tex_print_format(", options %x", glyph_options(p));
2681                        }
2682                        if (glyph_discpart(p)) {
2683                            tex_print_format(", discpart %i", glyph_discpart(p));
2684                        }
2685                        tex_aux_show_dictionary(p, glyph_properties(p), glyph_group(p), glyph_index(p), glyph_font(p), glyph_character(p));
2686                    }
2687                    tex_print_format(", font %F, glyph %U", glyph_font(p), glyph_character(p));
2688                    break;
2689                case hlist_node:
2690                case vlist_node:
2691                case unset_node:
2692                    /*tex Display box |p|. */
2693                    if (box_width(p)) {
2694                        tex_print_format(", width %p", box_width(p));
2695                    }
2696                    if (box_height(p)) {
2697                        tex_print_format(", height %p", box_height(p));
2698                    }
2699                    if (box_depth(p)) {
2700                        tex_print_format(", depth %p", box_depth(p));
2701                    }
2702                    if (node_type(p) == unset_node) {
2703                        /*tex Display special fields of the unset node |p|. */
2704                        if (box_span_count(p)) {
2705                            tex_print_format(", columns %i", box_span_count(p) + 1);
2706                        }
2707                        if (box_glue_stretch(p)) {
2708                            tex_print_str(", stretch ");
2709                            tex_print_glue(box_glue_stretch(p), box_glue_order(p), no_unit);
2710                        }
2711                        if (box_glue_shrink(p)) {
2712                            tex_print_str(", shrink ");
2713                            tex_print_glue(box_glue_shrink(p), box_glue_sign(p), no_unit);
2714                        }
2715                    } else {
2716                        /*tex
2717
2718                            Display the value of |glue_set(p)|. The code will have to change in
2719                            this place if |glue_ratio| is a structured type instead of an
2720                            ordinary |real|. Note that this routine should avoid arithmetic
2721                            errors even if the |glue_set| field holds an arbitrary random value.
2722                            The following code assumes that a properly formed nonzero |real|
2723                            number has absolute value $2^{20}$ or more when it is regarded as an
2724                            integer; this precaution was adequate to prevent floating point
2725                            underflow on the author's computer.
2726
2727                        */
2728                        double g = (double) (box_glue_set(p));
2729                        if ((g != 0.0) && (box_glue_sign(p) != normal_glue_sign)) {
2730                            tex_print_str(", glue "); /*tex This was |glue set|. */
2731                            if (box_glue_sign(p) == shrinking_glue_sign) {
2732                                tex_print_str("- ");
2733                            }
2734                            if (g > 20000.0 || g < -20000.0) {
2735                                if (g > 0.0) {
2736                                    tex_print_char('>');
2737                                } else {
2738                                    tex_print_str("< -");
2739                                }
2740                                tex_print_glue(20000 * unity, box_glue_order(p), no_unit);
2741                            } else {
2742                                tex_print_glue((scaled) glueround(unity *g), box_glue_order(p), no_unit);
2743                            }
2744                        }
2745                        if (box_shift_amount(p) != 0) {
2746                            tex_print_format(", shifted %p", box_shift_amount(p));
2747                        }
2748                        if (valid_direction(box_dir(p))) {
2749                            tex_print_format(", direction %2", box_dir(p));
2750                        }
2751                        if (box_geometry(p)) {
2752                            tex_print_format(", geometry %x", box_geometry(p));
2753                            if (tex_has_box_geometry(p, orientation_geometry)) {
2754                                tex_print_format(", orientation %x", box_orientation(p));
2755                            }
2756                            if (tex_has_box_geometry(p, offset_geometry)) {
2757                                tex_print_format(", offset(%p,%p)", box_x_offset(p), box_y_offset(p));
2758                            }
2759                            if (tex_has_box_geometry(p, anchor_geometry)) {
2760                                if (box_anchor(p)) {
2761                                    tex_print_format(", anchor %x", box_anchor(p));
2762                                }
2763                                if (box_source_anchor(p)) {
2764                                    tex_print_format(", source %i", box_source_anchor(p));
2765                                }
2766                                if (box_target_anchor(p)) {
2767                                    tex_print_format(", target %i", box_target_anchor(p));
2768                                }
2769                            }
2770                        }
2771                        if (box_index(p)) {
2772                            tex_print_format(", index %i", box_index(p));
2773                        }
2774                        if (box_package_state(p)) {
2775                            tex_print_format(", state %i", box_package_state(p));
2776                        }
2777                    }
2778                    tex_print_node_list(box_pre_adjusted(p), "preadjusted", threshold, max);
2779                    tex_print_node_list(box_pre_migrated(p), "premigrated", threshold, max);
2780                    tex_print_node_list(box_list(p), "list", threshold, max);
2781                    tex_print_node_list(box_post_migrated(p), "postmigrated", threshold, max);
2782                    tex_print_node_list(box_post_adjusted(p), "postadjusted", threshold, max);
2783                    break;
2784                case rule_node:
2785                    /*tex Display rule |p|. */
2786                    if (rule_width(p)) {
2787                        tex_print_format(", width %R", rule_width(p));
2788                    }
2789                    if (rule_height(p)) {
2790                        tex_print_format(", height %R", rule_height(p));
2791                    }
2792                    if (rule_depth(p)) {
2793                        tex_print_format(", depth %R", rule_depth(p));
2794                    }
2795                    switch (node_subtype(p)) { 
2796                        case virtual_rule_subtype:
2797                            if (rule_virtual_width(p)) {
2798                                tex_print_format(", virtual width %R", rule_virtual_width(p));
2799                            }
2800                            if (rule_virtual_height(p)) {
2801                                tex_print_format(", virtual height %R", rule_virtual_height(p));
2802                            }
2803                            if (rule_virtual_depth(p)) {
2804                                tex_print_format(", virtual depth %R", rule_virtual_depth(p));
2805                            }
2806                            break;
2807                        case strut_rule_subtype:
2808                            if (rule_strut_font(p)) {
2809                                if (rule_strut_font(p) >= rule_font_fam_offset) {
2810                                    tex_print_format(", family %i", rule_strut_font(p) - rule_font_fam_offset);
2811                                } else {
2812                                    tex_print_format(", font %F", rule_strut_font(p) < 0 ? 0 : rule_strut_font(p));
2813                                }
2814                            }
2815                            if (rule_strut_character(p)) {
2816                                tex_print_format(", character %U", rule_strut_character(p));
2817                            }
2818                            /* fall through */
2819                        default: 
2820                            if (rule_left(p)) {
2821                                tex_print_format(", left / top %R", rule_left(p));
2822                            }
2823                            if (rule_right(p)) {
2824                                tex_print_format(", right / bottom %R", rule_right(p));
2825                            }
2826                            break;
2827                    }
2828                    if (rule_x_offset(p)) {
2829                        tex_print_format(", xoffset %R", rule_x_offset(p));
2830                    }
2831                    if (rule_y_offset(p)) {
2832                        tex_print_format(", yoffset %R", rule_y_offset(p));
2833                    }
2834                    if (rule_data(p)) {
2835                        tex_print_format(", data %R", rule_data(p));
2836                    }
2837                    break;
2838                case insert_node:
2839                    /*tex Display insertion |p|. The natural size is the sum of height and depth. */
2840                    tex_print_format(
2841                        ", index %i, total height %p, max depth %p, split glue (", 
2842                        insert_index(p), 
2843                        insert_total_height(p),
2844                        insert_max_depth(p)
2845                    );
2846                    tex_print_specnode(insert_split_top(p), no_unit); /* todo: formatter for specnode but what CHAR to use */
2847                    tex_print_format(
2848                     "), float cost %i",
2849                        insert_float_cost(p)
2850                    );
2851                    tex_print_node_list(insert_list(p), "list", threshold, max);
2852                    break;
2853                case dir_node:
2854                    tex_print_format(", direction %2, level %i", dir_direction(p), dir_level(p));
2855                    break;
2856                case par_node:
2857                    {
2858                        halfword v;
2859                        /*tex We're already past processing so we only show the stored values. */
2860                        tex_print_format(", direction %2", par_dir(p));
2861                        if (node_subtype(p) == vmode_par_par_subtype) {
2862                            if (tex_par_state_is_set(p, par_par_shape_code)               ) { v = par_par_shape(p)               ; if (v)                     { tex_print_str(", parshape * ");              } }
2863                            if (tex_par_state_is_set(p, par_inter_line_penalties_code)    ) { v = par_inter_line_penalties(p)    ; if (v)                     { tex_print_str(", interlinepenalties * ");    } }
2864                            if (tex_par_state_is_set(p, par_club_penalties_code)          ) { v = par_club_penalties(p)          ; if (v)                     { tex_print_str(", clubpenalties * ");         } }
2865                            if (tex_par_state_is_set(p, par_widow_penalties_code)         ) { v = par_widow_penalties(p)         ; if (v)                     { tex_print_str(", widowpenalties * ");        } }
2866                            if (tex_par_state_is_set(p, par_display_widow_penalties_code) ) { v = par_display_widow_penalties(p) ; if (v)                     { tex_print_str(", displaywidowpenalties * "); } }
2867                            if (tex_par_state_is_set(p, par_orphan_penalties_code)        ) { v = par_orphan_penalties(p)        ; if (v)                     { tex_print_str(", orphanpenalties * ");       } }
2868                            if (tex_par_state_is_set(p, par_hang_indent_code)             ) { v = par_hang_indent(p)             ; if (v)                     { tex_print_str(", hangindent ");              tex_print_dimension(v, pt_unit); } }
2869                            if (tex_par_state_is_set(p, par_hang_after_code)              ) { v = par_hang_after(p)              ; if (v)                     { tex_print_str(", hangafter ");               tex_print_int      (v);          } }
2870                            if (tex_par_state_is_set(p, par_hsize_code)                   ) { v = par_hsize(p)                   ; if (v)                     { tex_print_str(", hsize ");                   tex_print_dimension(v, pt_unit); } }
2871                            if (tex_par_state_is_set(p, par_right_skip_code)              ) { v = par_right_skip(p)              ; if (! tex_glue_is_zero(v)) { tex_print_str(", rightskip ");               tex_print_specnode (v, pt_unit); } }
2872                            if (tex_par_state_is_set(p, par_left_skip_code)               ) { v = par_left_skip(p)               ; if (! tex_glue_is_zero(v)) { tex_print_str(", leftskip ");                tex_print_specnode (v, pt_unit); } }
2873                            if (tex_par_state_is_set(p, par_last_line_fit_code)           ) { v = par_last_line_fit(p)           ; if (v)                     { tex_print_str(", lastlinefit ");             tex_print_int      (v);          } }
2874                            if (tex_par_state_is_set(p, par_pre_tolerance_code)           ) { v = par_pre_tolerance(p)           ; if (v)                     { tex_print_str(", pretolerance ");            tex_print_int      (v);          } }
2875                            if (tex_par_state_is_set(p, par_tolerance_code)               ) { v = par_tolerance(p)               ; if (v)                     { tex_print_str(", tolerance ");               tex_print_int      (v);          } }
2876                            if (tex_par_state_is_set(p, par_looseness_code)               ) { v = par_looseness(p)               ; if (v)                     { tex_print_str(", looseness ");               tex_print_int      (v);          } }
2877                            if (tex_par_state_is_set(p, par_adjust_spacing_code)          ) { v = par_adjust_spacing(p)          ; if (v)                     { tex_print_str(", adjustspacing ");           tex_print_int      (v);          } }
2878                            if (tex_par_state_is_set(p, par_adj_demerits_code)            ) { v = par_adj_demerits(p)            ; if (v)                     { tex_print_str(", adjdemerits ");             tex_print_int      (v);          } }
2879                            if (tex_par_state_is_set(p, par_double_adj_demerits_code)     ) { v = par_double_adj_demerits(p)     ; if (v)                     { tex_print_str(", doubleadjdemerits ");       tex_print_int      (v);          } }
2880                            if (tex_par_state_is_set(p, par_protrude_chars_code)          ) { v = par_protrude_chars(p)          ; if (v)                     { tex_print_str(", protrudechars ");           tex_print_int      (v);          } }
2881                            if (tex_par_state_is_set(p, par_line_penalty_code)            ) { v = par_line_penalty(p)            ; if (v)                     { tex_print_str(", linepenalty ");             tex_print_int      (v);          } }
2882                            if (tex_par_state_is_set(p, par_double_hyphen_demerits_code)  ) { v = par_double_hyphen_demerits(p)  ; if (v)                     { tex_print_str(", doublehyphendemerits ");    tex_print_int      (v);          } }
2883                            if (tex_par_state_is_set(p, par_final_hyphen_demerits_code)   ) { v = par_final_hyphen_demerits(p)   ; if (v)                     { tex_print_str(", finalhyphendemerits ");     tex_print_int      (v);          } }
2884                            if (tex_par_state_is_set(p, par_inter_line_penalty_code)      ) { v = par_inter_line_penalty(p)      ; if (v)                     { tex_print_str(", interlinepenalty ");        tex_print_int      (v);          } }
2885                            if (tex_par_state_is_set(p, par_club_penalty_code)            ) { v = par_club_penalty(p)            ; if (v)                     { tex_print_str(", clubpenalty ");             tex_print_int      (v);          } }
2886                            if (tex_par_state_is_set(p, par_widow_penalty_code)           ) { v = par_widow_penalty(p)           ; if (v)                     { tex_print_str(", widowpenalty ");            tex_print_int      (v);          } }
2887                            if (tex_par_state_is_set(p, par_display_widow_penalty_code)   ) { v = par_display_widow_penalty(p)   ; if (v)                     { tex_print_str(", displaywidowpenalty ");     tex_print_int      (v);          } }
2888                            if (tex_par_state_is_set(p, par_orphan_penalty_code)          ) { v = par_orphan_penalty(p)          ; if (v)                     { tex_print_str(", orphanpenalty ");           tex_print_int      (v);          } }
2889                            if (tex_par_state_is_set(p, par_single_line_penalty_code)     ) { v = par_single_line_penalty(p)     ; if (v)                     { tex_print_str(", singlelinepenalty ");       tex_print_int      (v);          } }                                      
2890                            if (tex_par_state_is_set(p, par_broken_penalty_code)          ) { v = par_broken_penalty(p)          ; if (v)                     { tex_print_str(", brokenpenalty ");           tex_print_int      (v);          } }
2891                            if (tex_par_state_is_set(p, par_emergency_stretch_code)       ) { v = par_emergency_stretch(p)       ; if (v)                     { tex_print_str(", emergencystretch ");        tex_print_dimension(v, pt_unit); } }
2892                            if (tex_par_state_is_set(p, par_par_indent_code)              ) { v = par_par_indent(p)              ; if (v)                     { tex_print_str(", parindent ");               tex_print_dimension(v, pt_unit); } }
2893                            if (tex_par_state_is_set(p, par_par_fill_left_skip_code)      ) { v = par_par_fill_left_skip(p)      ; if (! tex_glue_is_zero(v)) { tex_print_str(", parfilleftskip ");          tex_print_specnode (v, pt_unit); } } 
2894                            if (tex_par_state_is_set(p, par_par_fill_right_skip_code)     ) { v = par_par_fill_right_skip(p)     ; if (! tex_glue_is_zero(v)) { tex_print_str(", parfillskip ");             tex_print_specnode (v, pt_unit); } } 
2895                            if (tex_par_state_is_set(p, par_par_init_left_skip_code)      ) { v = par_par_init_left_skip(p)      ; if (! tex_glue_is_zero(v)) { tex_print_str(", parinitleftskip ");         tex_print_specnode (v, pt_unit); } } 
2896                            if (tex_par_state_is_set(p, par_par_init_right_skip_code)     ) { v = par_par_init_right_skip(p)     ; if (! tex_glue_is_zero(v)) { tex_print_str(", parinitrightskip ");        tex_print_specnode (v, pt_unit); } } 
2897                            if (tex_par_state_is_set(p, par_emergency_left_skip_code)     ) { v = par_emergency_left_skip(p)     ; if (! tex_glue_is_zero(v)) { tex_print_str(", emergencyleftskip ");       tex_print_specnode (v, pt_unit); } } 
2898                            if (tex_par_state_is_set(p, par_emergency_right_skip_code)    ) { v = par_emergency_right_skip(p)    ; if (! tex_glue_is_zero(v)) { tex_print_str(", emergencyrightskip ");      tex_print_specnode (v, pt_unit); } } 
2899                            if (tex_par_state_is_set(p, par_baseline_skip_code)           ) { v = par_baseline_skip(p)           ; if (! tex_glue_is_zero(v)) { tex_print_str(", baselineskip ");            tex_print_specnode (v, pt_unit); } } 
2900                            if (tex_par_state_is_set(p, par_line_skip_code)               ) { v = par_line_skip(p)               ; if (! tex_glue_is_zero(v)) { tex_print_str(", lineskip ");                tex_print_specnode (v, pt_unit); } } 
2901                            if (tex_par_state_is_set(p, par_line_skip_limit_code)         ) { v = par_line_skip_limit(p)         ; if (v)                     { tex_print_str(", lineskiplimt ");            tex_print_dimension(v, pt_unit); } }
2902                            if (tex_par_state_is_set(p, par_adjust_spacing_step_code)     ) { v = par_adjust_spacing_step(p)     ; if (v > 0)                 { tex_print_str(", adjustspacingstep ");       tex_print_int      (v);          } }
2903                            if (tex_par_state_is_set(p, par_adjust_spacing_shrink_code)   ) { v = par_adjust_spacing_shrink(p)   ; if (v > 0)                 { tex_print_str(", adjustspacingshrink ");     tex_print_int      (v);          } }
2904                            if (tex_par_state_is_set(p, par_adjust_spacing_stretch_code)  ) { v = par_adjust_spacing_stretch(p)  ; if (v > 0)                 { tex_print_str(", adjustspacingstretch ");    tex_print_int      (v);          } }
2905                            if (tex_par_state_is_set(p, par_hyphenation_mode_code)        ) { v = par_hyphenation_mode(p)        ; if (v > 0)                 { tex_print_str(", hyphenationmode ");         tex_print_int      (v);          } }
2906                            if (tex_par_state_is_set(p, par_shaping_penalties_mode_code)  ) { v = par_shaping_penalties_mode(p)  ; if (v > 0)                 { tex_print_str(", shapingpenaltiesmode ");    tex_print_int      (v);          } }
2907                            if (tex_par_state_is_set(p, par_shaping_penalty_code)         ) { v = par_shaping_penalty(p)         ; if (v > 0)                 { tex_print_str(", shapingpenalty ");          tex_print_int      (v);          } }
2908                            if (tex_par_state_is_set(p, par_emergency_extra_stretch_code) ) { v = par_emergency_extra_stretch(p) ; if (v)                     { tex_print_str(", emergencyextrastretch ");   tex_print_dimension(v, pt_unit); } }
2909                            if (tex_par_state_is_set(p, par_par_passes_code)              ) { v = par_par_passes(p)              ; if (v)                     { tex_print_str(", parpasses * ");                                              } }
2910                        }
2911                        /* local boxes */
2912                        v = tex_get_local_left_width(p)  ; if (v) { tex_print_format(", leftboxwidth %p", v); }
2913                        v = tex_get_local_right_width(p) ; if (v) { tex_print_format(", rightboxwidth %p", v); }
2914                        tex_print_node_list(par_box_left(p), "leftbox", threshold, max);
2915                        tex_print_node_list(par_box_right(p), "rightbox", threshold, max);
2916                        tex_print_node_list(par_box_middle(p), "middlebox", threshold, max);
2917                    }
2918                    break;
2919                case boundary_node:
2920                    if (boundary_data(p)) {
2921                        tex_print_format(", data %i", boundary_data(p));
2922                    }
2923                    break;
2924                case whatsit_node:
2925                    {
2926                        int callback_id = lmt_callback_defined(show_whatsit_callback);
2927                        /*tex we always print this */
2928                        if (callback_id) {
2929                            strnumber u = tex_save_cur_string();
2930                            char *s = NULL;
2931                            lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "Nd->S", p, 1, &s);
2932                            tex_restore_cur_string(u);
2933                            if (s) {
2934                                tex_aux_print_subtype_and_attributes_str(p, s);
2935                                lmt_memory_free(s);
2936                            } else {
2937                                tex_aux_print_subtype_and_attributes_int(p, node_subtype(p));
2938                            }
2939                        } else {
2940                            tex_aux_print_subtype_and_attributes_int(p, node_subtype(p));
2941                        }
2942                        /*tex but optionally there can be more */
2943                        if (callback_id) {
2944                            int l = lmt_string_pool_state.string_temp_top / 2;
2945                            strnumber u = tex_save_cur_string();
2946                            /*tex Todo: the tracing needs checking. */
2947                            lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "Nddddd->", p, 2, l, (tracing_levels_par & (tracing_levels_group | tracing_levels_input)), cur_level, lmt_input_state.input_stack_data.ptr);
2948                            tex_restore_cur_string(u);
2949                        }
2950                    }
2951                    break;
2952                case glue_node:
2953                    /*tex Display glue |p|. */
2954                    if (is_leader(p)) {
2955                        /*tex Display leaders |p|. */
2956                        tex_print_str(", leader ");
2957                        tex_print_specnode(p, no_unit);
2958                        tex_print_node_list(glue_leader_ptr(p), "list", threshold, max);
2959                    } else {
2960                        if (node_subtype(p) != conditional_math_glue && node_subtype(p) != rulebased_math_glue) {
2961                            tex_print_char(' ');
2962                            tex_print_specnode(p, node_subtype(p) < conditional_math_glue ? pt_unit : mu_unit); /* was |no_unit : mu_unit| */
2963                        }
2964                        if (glue_data(p)) {
2965                            tex_print_format(", data %i", glue_data(p));
2966                        }
2967                        if (node_subtype(p) == space_skip_glue && glue_font(p)) {
2968                            tex_print_format(", font %i", glue_font(p));
2969                        }
2970                        if (glue_options(p)) {
2971                            tex_print_format(", options %x", glue_options(p));
2972                        }
2973                    }
2974                    break;
2975                case kern_node:
2976                    /*tex Display kern |p| */
2977                    if (node_subtype(p) != explicit_math_kern_subtype) {
2978                        tex_print_format(", amount %p", kern_amount(p));
2979                        if (kern_expansion(p)) {
2980                            tex_print_format(", expansion %i", kern_expansion(p));
2981                        }
2982                    } else {
2983                        tex_print_format(", amount %D", kern_amount(p), mu_unit);
2984                    }
2985                    break;
2986                case math_node:
2987                    /*tex Display math node |p|. */
2988                    if (! tex_math_glue_is_zero(p)) {
2989                        tex_print_str(", glued ");
2990                        tex_print_specnode(p, no_unit);
2991                    } else if (math_surround(p)) {
2992                        tex_print_format(", surrounded %p", math_surround(p));
2993                    }
2994                    if (math_penalty(p)) {
2995                        tex_print_format(", penalty %i", math_penalty(p));
2996                    }
2997                    if (math_pre_tolerance(p)) {
2998                        tex_print_format(", pretolerance %i", math_pre_tolerance(p));
2999                    }
3000                    if (math_tolerance(p)) {
3001                        tex_print_format(", tolerance %i", math_tolerance(p));
3002                    }
3003                    if (math_options(p)) {
3004                        tex_print_format(", options %x", math_options(p));
3005                    }
3006                    break;
3007                case penalty_node:
3008                    /*tex Display penalty |p|. */
3009                    tex_print_format(", amount %i", penalty_amount(p));
3010                    break;
3011                case disc_node:
3012                    if (disc_class(p) != unset_disc_class) {
3013                        tex_print_format(", class %i", disc_class(p));
3014                    }
3015                    if (disc_options(p)) {
3016                        tex_print_format(", options %x", disc_options(p));
3017                    }
3018                    tex_print_format(", penalty %i", disc_penalty(p));
3019                    tex_print_node_list(disc_pre_break_head(p), "prebreaklist", threshold, max);
3020                    tex_print_node_list(disc_post_break_head(p), "postbreaklist", threshold, max);
3021                    tex_print_node_list(disc_no_break_head(p), "nobreaklist", threshold, max);
3022                    break;
3023                case mark_node:
3024                    /*tex Display mark |p|. */
3025                    tex_print_format(", index %i", mark_index(p));
3026                    if (node_subtype(p) == reset_mark_value_code) {
3027                        tex_print_str(", reset");
3028                    } else {
3029                        tex_print_token_list(NULL, token_link(mark_ptr(p))); /*tex We have a ref count token. */
3030                    }
3031                    break;
3032                case adjust_node:
3033                    /*tex Display adjustment |p|. */
3034                    if (adjust_options(p)) {
3035                        tex_print_format(", options %x", adjust_options(p));
3036                    }
3037                    if (adjust_index(p)) {
3038                        tex_print_format(", index %i", adjust_index(p));
3039                    }
3040                    if (has_adjust_option(p, adjust_option_depth_before) && adjust_depth_before(p)) {
3041                        tex_print_format(", depthbefore %p", adjust_depth_before(p));
3042                    }
3043                    if (has_adjust_option(p, adjust_option_depth_after) &&adjust_depth_before(p)) {
3044                        tex_print_format(", depthafter %p", adjust_depth_after(p));
3045                    }
3046                    tex_print_node_list(adjust_list(p), "list", threshold, max);
3047                    break;
3048                case glue_spec_node:
3049                case math_spec_node:
3050                case font_spec_node:
3051                    /*tex This is actually an error! */
3052                    break;
3053                case align_record_node:
3054                    tex_print_token_list(NULL, align_record_pre_part(p)); /*tex No ref count token here. */
3055                    tex_print_levels();
3056                    tex_print_str("..<content>");
3057                    tex_print_token_list(NULL, align_record_post_part(p)); /*tex No ref count token here. */
3058                    break;
3059                case temp_node:
3060                    break;
3061                default:
3062                    if (! tex_show_math_node(p, threshold, max)) {
3063                        tex_print_format("<unknown node type %i>", node_type(p));
3064                    }
3065                    break;
3066            }
3067            p = node_next(p);
3068        }
3069    }
3070}
3071
3072/*tex
3073
3074    This routine finds the base width of a horizontal box, using the same logic that \TEX82\ used
3075    for |\predisplaywidth|.
3076
3077*/
3078
3079static halfword tex_aux_get_actual_box_width(halfword r, halfword p, scaled initial_width)
3080{
3081    /*tex calculated |size| */
3082    scaled w = -max_dimension;
3083    /*tex |w| plus possible glue amount */
3084    scaled v = initial_width;
3085    while (p) {
3086        /*tex increment to |v| */
3087        scaled d;
3088        switch (node_type(p)) {
3089            case glyph_node:
3090                d = tex_glyph_width(p);
3091                goto FOUND;
3092            case hlist_node:
3093            case vlist_node:
3094                d = box_width(p);
3095                goto FOUND;
3096            case rule_node:
3097                d = rule_width(p);
3098                goto FOUND;
3099            case kern_node:
3100                d = kern_amount(p);
3101                break;
3102            case disc_node:
3103                /*tex At the end of the line we should actually take the |pre|. */
3104                if (disc_no_break(p)) {
3105                    d = tex_aux_get_actual_box_width(r, disc_no_break_head(p),0);
3106                    if (d <= -max_dimension || d >= max_dimension) {
3107                        d = 0;
3108                    }
3109                } else {
3110                    d = 0;
3111                }
3112                goto FOUND;
3113            case math_node:
3114                if (tex_math_glue_is_zero(p)) {
3115                    d = math_surround(p);
3116                } else {
3117                    d = math_amount(p);
3118                    switch (box_glue_sign(r)) {
3119                        case stretching_glue_sign:
3120                            if ((box_glue_order(r) == math_stretch_order(p)) && math_stretch(p)) {
3121                                v = max_dimension;
3122                            }
3123                            break;
3124                        case shrinking_glue_sign:
3125                            if ((box_glue_order(r) == math_shrink_order(p)) && math_shrink(p)) {
3126                                v = max_dimension;
3127                            }
3128                            break;
3129                    }
3130                break;
3131                }
3132                break;
3133            case glue_node:
3134                /*tex
3135                    We need to be careful that |w|, |v|, and |d| do not depend on any |glue_set|
3136                    values, since such values are subject to system-dependent rounding. System
3137                    dependent numbers are not allowed to infiltrate parameters like
3138                    |pre_display_size|, since \TEX82 is supposed to make the same decisions on
3139                    all machines.
3140                */
3141                d = glue_amount(p);
3142                if (box_glue_sign(r) == stretching_glue_sign) {
3143                    if ((box_glue_order(r) == glue_stretch_order(p)) && glue_stretch(p)) {
3144                        v = max_dimension;
3145                    }
3146                } else if (box_glue_sign(r) == shrinking_glue_sign) {
3147                    if ((box_glue_order(r) == glue_shrink_order(p)) && glue_shrink(p)) {
3148                        v = max_dimension;
3149                    }
3150                }
3151                if (is_leader(p)) {
3152                    goto FOUND;
3153                }
3154                break;
3155            default:
3156                d = 0;
3157                break;
3158        }
3159        if (v < max_dimension) {
3160            v += d;
3161        }
3162        goto NOT_FOUND;
3163      FOUND:
3164        if (v < max_dimension) {
3165            v += d;
3166            w = v;
3167        } else {
3168            w = max_dimension;
3169            break;
3170        }
3171      NOT_FOUND:
3172        p = node_next(p);
3173    }
3174    return w;
3175}
3176
3177halfword tex_actual_box_width(halfword r, scaled base_width)
3178{
3179    /*tex
3180
3181        Often this is the same as:
3182
3183        \starttyping
3184        return + shift_amount(r) + base_width +
3185            natural_sizes(list_ptr(r),null,(glueratio) box_glue_set(r),box_glue_sign(r),box_glue_order(r),box_dir(r));
3186        \stoptyping
3187    */
3188    return tex_aux_get_actual_box_width(r, box_list(r), box_shift_amount(r) + base_width);
3189}
3190
3191int tex_list_has_glyph(halfword list)
3192{
3193    while (list) {
3194        switch (node_type(list)) {
3195            case glyph_node:
3196            case disc_node:
3197                return 1;
3198            default:
3199                list = node_next(list);
3200                break;
3201        }
3202    }
3203    return 0;
3204}
3205
3206/*tex
3207
3208    Attribute lists need two extra globals to increase processing efficiency. |max_used_attr|
3209    limits the test loop that checks for set attributes, and |attr_cache| contains a pointer to an
3210    already created attribute list. It is set to the special value |cache_disabled| when the
3211    current value can no longer be trusted: after an assignment to an attribute register, and after
3212    a group has ended.
3213
3214    From the computer's standpoint, \TEX's chief mission is to create horizontal and vertical
3215    lists. We shall now investigate how the elements of these lists are represented internally as
3216    nodes in the dynamic memory.
3217
3218    A horizontal or vertical list is linked together by |link| fields in the first word of each
3219    node. Individual nodes represent boxes, glue, penalties, or special things like discretionary
3220    hyphens; because of this variety, some nodes are longer than others, and we must distinguish
3221    different kinds of nodes. We do this by putting a |type| field in the first word, together
3222    with the link and an optional |subtype|.
3223
3224    Character nodes appear only in horizontal lists, never in vertical lists.
3225
3226    An |hlist_node| stands for a box that was made from a horizontal list. Each |hlist_node| is
3227    seven words long, and contains the following fields (in addition to the mandatory |type| and
3228    |link|, which we shall not mention explicitly when discussing the other node types): The
3229    |height| and |width| and |depth| are scaled integers denoting the dimensions of the box. There
3230    is also a |shift_amount| field, a scaled integer indicating how much this box should be
3231    lowered (if it appears in a horizontal list), or how much it should be moved to the right (if
3232    it appears in a vertical list). There is a |list_ptr| field, which points to the beginning of
3233    the list from which this box was fabricated; if |list_ptr| is |null|, the box is empty. Finally,
3234    there are three fields that represent the setting of the glue: |glue_set(p)| is a word of type
3235    |glue_ratio| that represents the proportionality constant for glue setting; |glue_sign(p)| is
3236    |stretching| or |shrinking| or |normal| depending on whether or not the glue should stretch or
3237    shrink or remain rigid; and |glue_order(p)| specifies the order of infinity to which glue
3238    setting applies (|normal|, |sfi|, |fil|, |fill|, or |filll|). The |subtype| field is not used.
3239
3240    The |new_null_box| function returns a pointer to an |hlist_node| in which all subfields have
3241    the values corresponding to |\hbox{}|. The |subtype| field is set to |min_quarterword|, since
3242    that's the desired |span_count| value if this |hlist_node| is changed to an |unset_node|.
3243
3244*/
3245
3246/*tex Create a new box node. */
3247
3248halfword tex_new_null_box_node(quarterword t, quarterword s)
3249{
3250 // halfword p = tex_new_node(hlist_node, min_quarterword);
3251    halfword p = tex_new_node(t, s);
3252    box_dir(p) = (singleword) text_direction_par;
3253    return p;
3254}
3255
3256/*tex
3257
3258    A |vlist_node| is like an |hlist_node| in all respects except that it contains a vertical list.
3259
3260    A |rule_node| stands for a solid black rectangle; it has |width|, |depth|, and |height| fields
3261    just as in an |hlist_node|. However, if any of these dimensions is $-2^{30}$, the actual value
3262    will be determined by running the rule up to the boundary of the innermost enclosing box. This
3263    is called a \quote {running dimension}. The |width| is never running in an hlist; the |height|
3264    and |depth| are never running in a~vlist.
3265
3266    A new rule node is delivered by the |new_rule| function. It makes all the dimensions \quote
3267    {running}, so you have to change the ones that are not allowed to run.
3268
3269*/
3270
3271halfword tex_new_rule_node(quarterword s)
3272{
3273    return tex_new_node(rule_node, s);
3274}
3275
3276/*tex
3277
3278    Insertions are represented by |insert_node| records, where the |subtype| indicates the
3279    corresponding box number. For example, |\insert 250| leads to an |insert_node| whose |subtype|
3280    is |250 + min_quarterword|. The |height| field of an |insert_node| is slightly misnamed; it
3281    actually holds the natural height plus depth of the vertical list being inserted. The |depth|
3282    field holds the |split_max_depth| to be used in case this insertion is split, and the
3283    |split_top_ptr| points to the corresponding |split_top_skip|. The |float_cost| field holds the
3284    |floating_penalty| that will be used if this insertion floats to a subsequent page after a
3285    split insertion of the same class. There is one more field, the |insert_ptr|, which points to the
3286    beginning of the vlist for the insertion.
3287
3288    A |mark_node| has a |mark_ptr| field that points to the reference count of a token list that
3289    contains the user's |\mark| text. In addition there is a |mark_class| field that contains the
3290    mark class.
3291
3292    An |adjust_node|, which occurs only in horizontal lists, specifies material that will be moved
3293    out into the surrounding vertical list; i.e., it is used to implement \TEX's |\vadjust|
3294    operation. The |adjust_ptr| field points to the vlist containing this material.
3295
3296    A |glyph_node|, which occurs only in horizontal lists, specifies a glyph in a particular font,
3297    along with its attribute list. Older versions of \TEX\ could use token memory for characters,
3298    because the font,char combination would fit in a single word (both values were required to be
3299    strictly less than $2^{16}$). In \LUATEX, room is needed for characters that are larger than
3300    that, as well as a pointer to a potential attribute list, and the two displacement values.
3301
3302    In turn, that made the node so large that it made sense to merge ligature glyphs as well, as
3303    that requires only one extra pointer. A few extra classes of glyph nodes will be introduced
3304    later. The unification of all those types makes it easier to manipulate lists of glyphs. The
3305    subtype differentiates various glyph kinds.
3306
3307    First, here is a function that returns a pointer to a glyph node for a given glyph in a given
3308    font. If that glyph doesn't exist, |null| is returned instead. Nodes of this subtype are
3309    directly created only for accents and their base (through |make_accent|), and math nucleus
3310    items (in the conversion from |mlist| to |hlist|).
3311
3312    We no longer check if the glyph exists because a replacement can be used instead. We copy some
3313    properties when there is a parent passed.
3314
3315*/
3316
3317halfword tex_new_glyph_node(quarterword s, halfword f, halfword c, halfword parent)
3318{
3319    halfword p = parent  && node_type(parent) == glyph_node ? tex_copy_node(parent) : tex_aux_new_glyph_node_with_attributes(parent);
3320    node_subtype(p) = s;
3321    glyph_font(p) = f;
3322    glyph_character(p) = c;
3323    tex_char_process(f, c);
3324    return p;
3325}
3326
3327/*tex
3328
3329    A subset of the glyphs nodes represent ligatures: characters fabricated from the interaction
3330    of two or more actual characters. The characters that generated the ligature have not been
3331    forgotten, since they are needed for diagnostic messages; the |lig_ptr| field points to a
3332    linked list of character nodes for all original characters that have been deleted. (This list
3333    might be empty if the characters that generated the ligature were retained in other nodes.)
3334    Remark: we no longer keep track of ligatures via |lig_ptr| because there is no guarantee that
3335    they are consistently tracked; they are something internal anyway. Of course one can provide an
3336    alternative at the \LUA\ end (which is what we do in \CONTEXT).
3337
3338    The |subtype| field of these |glyph_node|s is 1, plus 2 and/or 1 if the original source of the
3339    ligature included implicit left and/or right boundaries. These nodes are created by the C
3340    function |new_ligkern|.
3341
3342    A third general type of glyphs could be called a character, as it only appears in lists that
3343    are not yet processed by the ligaturing and kerning steps of the program.
3344
3345    |main_control| inserts these, and they are later converted to |subtype_normal| by |new_ligkern|.
3346
3347*/
3348
3349/*
3350quarterword norm_min(int h)
3351{
3352    if (h <= 0)
3353        return 1;
3354    else if (h >= 255)
3355        return 255;
3356    else
3357        return (quarterword) h;
3358}
3359*/
3360
3361halfword tex_new_char_node(quarterword subtype, halfword fnt, halfword chr, int all)
3362{
3363    halfword p = tex_aux_new_glyph_node_with_attributes(null);
3364    node_subtype(p) = subtype;
3365    glyph_font(p) = fnt;
3366    glyph_character(p) = chr;
3367    if (all) {
3368        glyph_data(p) = glyph_data_par;
3369        /* no state */
3370        set_glyph_script(p, glyph_script_par);
3371        set_glyph_language(p, cur_lang_par);
3372        set_glyph_lhmin(p, left_hyphen_min_par);
3373        set_glyph_rhmin(p, right_hyphen_min_par);
3374        set_glyph_hyphenate(p, hyphenation_mode_par);
3375        set_glyph_options(p, glyph_options_par);
3376        set_glyph_scale(p, glyph_scale_par);
3377        set_glyph_x_scale(p, glyph_x_scale_par);
3378        set_glyph_y_scale(p, glyph_y_scale_par);
3379        set_glyph_x_offset(p, glyph_x_offset_par);
3380        set_glyph_y_offset(p, glyph_y_offset_par);
3381        set_glyph_slant(p, glyph_slant_par);
3382        set_glyph_weight(p, glyph_weight_par);
3383    }
3384    if (! tex_char_exists(fnt, chr)) {
3385        int callback_id = lmt_callback_defined(missing_character_callback);
3386        if (callback_id > 0) {
3387            /* maybe direct node */
3388            lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "Ndd->", p, fnt, chr);
3389        }
3390    }
3391    return p;
3392}
3393
3394halfword tex_new_text_glyph(halfword fnt, halfword chr)
3395{
3396    halfword p = tex_get_node(glyph_node_size);
3397    memset((void *) (lmt_node_memory_state.nodes + p + 1), 0, (sizeof(memoryword) * (glyph_node_size - 1)));
3398    node_type(p) = glyph_node;
3399    node_subtype(p) = glyph_unset_subtype;
3400    glyph_font(p) = fnt;
3401    glyph_character(p) = chr;
3402    glyph_data(p) = glyph_data_par;
3403    /* no state */
3404    set_glyph_script(p, glyph_script_par);
3405    set_glyph_language(p, cur_lang_par);
3406    set_glyph_lhmin(p, left_hyphen_min_par);
3407    set_glyph_rhmin(p, right_hyphen_min_par);
3408    set_glyph_hyphenate(p, hyphenation_mode_par);
3409    set_glyph_options(p, glyph_options_par);
3410    set_glyph_scale(p, glyph_scale_par);
3411    set_glyph_x_scale(p, glyph_x_scale_par);
3412    set_glyph_y_scale(p, glyph_y_scale_par);
3413    set_glyph_x_offset(p, glyph_x_offset_par);
3414    set_glyph_y_offset(p, glyph_y_offset_par);
3415    set_glyph_slant(p, glyph_slant_par);
3416    set_glyph_weight(p, glyph_weight_par);
3417    return p;
3418}
3419
3420/*tex
3421
3422    Here are a few handy helpers used by the list output routines.
3423
3424    We had an xadvance but dropped it but it might come back eventually. The offsets are mostly
3425    there to deal with anchoring and we assume kerns to be used to complement x offsets if needed:
3426    just practical decisions made long ago.
3427
3428    Why do we check y offset being positive for dp but not for ht? Maybe change this to be
3429    consistent? Anyway, we have adapted \LUATEX\ so ...
3430
3431    \startitemize
3432    \startitem what we had before \stopitem
3433    \startitem compensate height and depth \stopitem
3434    \startitem compensate height and depth, take max \stopitem
3435    \startitem we keep height and depth \stopitem
3436    \stopitemize
3437
3438*/
3439
3440/*tex These should move to the texfont.c as we have too many variants now. */
3441
3442scaled tex_glyph_width(halfword p)
3443{
3444    scaled w = tex_char_width_from_glyph(p);
3445    scaled x = glyph_x_offset(p);
3446    if (x && tex_has_glyph_option(p, glyph_option_apply_x_offset)) {
3447        w += x; /* or after expansion? needs testing */
3448    }
3449    w -= (glyph_left(p) + glyph_right(p));
3450    return w;
3451}
3452
3453scaled tex_glyph_width_ex(halfword p)
3454{
3455    scaled w = tex_char_width_from_glyph(p);
3456    scaled x = glyph_x_offset(p);
3457    if (x && tex_has_glyph_option(p, glyph_option_apply_x_offset)) {
3458        w += x; /* or after expansion? needs testing */
3459    }
3460    w -= (glyph_left(p) + glyph_right(p));
3461    if (glyph_expansion(p)) {
3462        w = w + tex_ext_xn_over_d(w, scaling_factor_squared + glyph_expansion(p), scaling_factor_squared);
3463    }
3464    return w;
3465}
3466
3467scaled tex_glyph_height(halfword p)
3468{
3469    scaled h = tex_char_height_from_glyph(p) + glyph_raise(p);
3470    scaled y = glyph_y_offset(p);
3471    if (y && tex_has_glyph_option(p, glyph_option_apply_y_offset)) {
3472        h += y;
3473    }
3474    return h < 0 ? 0 : h;
3475}
3476
3477scaled tex_glyph_depth(halfword p) /* not used */
3478{
3479    scaled d = tex_char_depth_from_glyph(p) - glyph_raise(p);
3480    scaled y = glyph_y_offset(p);
3481    if (y && tex_has_glyph_option(p, glyph_option_apply_y_offset)) {
3482        d -= y;
3483    }
3484    return d < 0 ? 0 : d;
3485}
3486
3487scaledwhd tex_glyph_dimensions(halfword p)
3488{
3489    scaledwhd whd = tex_char_whd_from_glyph(p);
3490    scaled x = glyph_x_offset(p);
3491    scaled y = glyph_y_offset(p);
3492    whd.ht += glyph_raise(p);
3493    whd.dp -= glyph_raise(p);
3494    whd.wd += (glyph_left(p) + glyph_right(p));
3495    if (x && tex_has_glyph_option(p, glyph_option_apply_x_offset)) {
3496        whd.wd += x;
3497    }
3498    if (y && tex_has_glyph_option(p, glyph_option_apply_y_offset)) {
3499        whd.ht += y;
3500        whd.dp -= y;
3501    }
3502    if (whd.ht < 0) {
3503        whd.ht = 0;
3504    }
3505    if (whd.dp < 0) {
3506        whd.dp = 0;
3507    }
3508    return whd;
3509}
3510
3511scaledwhd tex_glyph_dimensions_ex(halfword p)
3512{
3513    scaledwhd whd = tex_char_whd_from_glyph(p);
3514    scaled x = glyph_x_offset(p);
3515    scaled y = glyph_y_offset(p);
3516    whd.ht += glyph_raise(p);
3517    whd.dp -= glyph_raise(p);
3518    whd.wd -= (glyph_left(p) + glyph_right(p));
3519    if (x && tex_has_glyph_option(p, glyph_option_apply_x_offset)) {
3520        whd.wd += x;
3521    }
3522    if (y && tex_has_glyph_option(p, glyph_option_apply_y_offset)) {
3523        whd.ht += y;
3524        whd.dp -= y;
3525    }
3526    if (whd.ht < 0) {
3527        whd.ht = 0;
3528    }
3529    if (whd.dp < 0) {
3530        whd.dp = 0;
3531    }
3532    if (whd.wd && glyph_expansion(p)) {
3533        whd.wd = tex_ext_xn_over_d(whd.wd, scaling_factor_squared + glyph_expansion(p), scaling_factor_squared);
3534    }
3535    return whd;
3536}
3537
3538scaled tex_glyph_total(halfword p)
3539{
3540    return tex_char_total_from_glyph(p);
3541}
3542
3543int tex_glyph_has_dimensions(halfword p)
3544{
3545    scaledwhd whd = tex_char_whd_from_glyph(p);
3546    scaled offset = glyph_x_offset(p);
3547    scaled amount = whd.wd;
3548    if (offset && tex_has_glyph_option(p, glyph_option_apply_x_offset)) {
3549        amount += offset;
3550    }
3551    amount -= (glyph_left(p) + glyph_right(p));
3552    if (amount) {
3553        return 1;
3554    } else {
3555        /* here offset and raise just moves */
3556        return whd.ht > 0 || whd.dp > 0;
3557    }
3558}
3559
3560halfword tex_kern_dimension(halfword p)
3561{
3562    return kern_amount(p);
3563}
3564
3565halfword tex_kern_dimension_ex(halfword p)
3566{
3567    halfword k = kern_amount(p);
3568    if (k && kern_expansion(p)) {
3569        k = tex_ext_xn_over_d(k, scaling_factor_squared + kern_expansion(p), scaling_factor_squared);
3570    }
3571    return k;
3572}
3573
3574scaledwhd tex_pack_dimensions(halfword p)
3575{
3576    scaledwhd siz = { .wd = 0, .ht = 0, .dp = 0, .ns = 0 };
3577    siz.ht = box_height(p);
3578    siz.dp = box_depth(p);
3579    siz.wd = box_width(p);
3580    return siz;
3581}
3582
3583/*tex
3584
3585    A |disc_node|, which occurs only in horizontal lists, specifies a \quote {discretionary}
3586    line break. If such a break occurs at node |p|, the text that starts at |pre_break(p)| will
3587    precede the break, the text that starts at |post_break(p)| will follow the break, and text
3588    that appears in |no_break(p)| nodes will be ignored. For example, an ordinary discretionary
3589    hyphen, indicated by |\-|, yields a |disc_node| with |pre_break| pointing to a |char_node|
3590    containing a hyphen, |post_break = null|, and |no_break=null|.
3591
3592    If |subtype(p) = automatic_disc|, the |ex_hyphen_penalty| will be charged for this break.
3593    Otherwise the |hyphen_penalty| will be charged. The texts will actually be substituted into
3594    the list by the line-breaking algorithm if it decides to make the break, and the discretionary
3595    node will disappear at that time; thus, the output routine sees only discretionaries that were
3596    not chosen.
3597
3598*/
3599
3600halfword tex_new_disc_node(quarterword s)
3601{
3602    halfword p = tex_new_node(disc_node, s);
3603    disc_penalty(p) = hyphen_penalty_par;
3604    disc_class(p) = unset_disc_class;
3605    set_disc_options(p, discretionary_options_par);
3606    return p;
3607}
3608
3609/*tex
3610
3611    The program above includes a bunch of \quote {hooks} that allow further capabilities to be
3612    added without upsetting \TEX's basic structure. Most of these hooks are concerned with \quote
3613    {whatsit} nodes, which are intended to be used for special purposes; whenever a new extension
3614    to \TEX\ involves a new kind of whatsit node, a corresponding change needs to be made to the
3615    routines below that deal with such nodes, but it will usually be unnecessary to make many
3616    changes to the other parts of this program.
3617
3618    In order to demonstrate how extensions can be made, we shall treat |\write|, |\openout|,
3619    |\closeout|, |\immediate|, and |\special| as if they were extensions. These commands are
3620    actually primitives of \TEX, and they should appear in all implementations of the system; but
3621    let's try to imagine that they aren't. Then the program below illustrates how a person could
3622    add them.
3623
3624    Sometimes, of course, an extension will require changes to \TEX\ itself; no system of hooks
3625    could be complete enough for all conceivable extensions. The features associated with |\write|
3626    are almost all confined to the following paragraphs, but there are small parts of the |print_ln|
3627    and |print_char| procedures that were introduced specifically to |\write| characters.
3628    Furthermore one of the token lists recognized by the scanner is a |write_text|; and there are a
3629    few other miscellaneous places where we have already provided for some aspect of |\write|. The
3630    goal of a \TeX\ extender should be to minimize alterations to the standard parts of the program,
3631    and to avoid them completely if possible. He or she should also be quite sure that there's no
3632    easy way to accomplish the desired goals with the standard features that \TEX\ already has.
3633    \quote {Think thrice before extending}, because that may save a lot of work, and it will also
3634    keep incompatible extensions of \TEX\ from proliferating.
3635
3636    First let's consider the format of whatsit nodes that are used to represent the data associated
3637    with |\write| and its relatives. Recall that a whatsit has |type=whatsit_node|, and the |subtype|
3638    is supposed to distinguish different kinds of whatsits. Each node occupies two or more words;
3639    the exact number is immaterial, as long as it is readily determined from the |subtype| or other
3640    data.
3641
3642    We shall introduce five |subtype| values here, corresponding to the control sequences |\openout|,
3643    |\write|, |\closeout|, and |\special|. The second word of I/O whatsits has a |write_stream|
3644    field that identifies the write-stream number (0 to 15, or 16 for out-of-range and positive, or
3645    17 for out-of-range and negative). In the case of |\write| and |\special|, there is also a field
3646    that points to the reference count of a token list that should be sent. In the case of |\openout|,
3647    we need three words and three auxiliary subfields to hold the string numbers for name, area, and
3648    extension.
3649
3650    Extensions might introduce new command codes; but it's best to use |extension| with a modifier,
3651    whenever possible, so that |main_control| stays the same.
3652
3653    The sixteen possible |\write| streams are represented by the |write_file| array. The |j|th file
3654    is open if and only if |write_open[j]=true|. The last two streams are special; |write_open[16]|
3655    represents a stream number greater than 15, while |write_open[17]| represents a negative stream
3656    number, and both of these variables are always |false|.
3657
3658    Writing to files is delegated to \LUA, so we have no write channels.
3659
3660    To write a token list, we must run it through \TEX's scanner, expanding macros and |\the| and
3661    |\number|, etc. This might cause runaways, if a delimited macro parameter isn't matched, and
3662    runaways would be extremely confusing since we are calling on \TEX's scanner in the middle of
3663    a |\shipout| command. Therefore we will put a dummy control sequence as a \quote {stopper},
3664    right after the token list. This control sequence is artificially defined to be |\outer|.
3665
3666    The presence of |\immediate| causes the |do_extension| procedure to descend to one level of
3667    recursion. Nothing happens unless |\immediate| is followed by |\openout|, |\write|, or
3668    |\closeout|.
3669
3670    Here is a subroutine that creates a whatsit node having a given |subtype| and a given number
3671    of words. It initializes only the first word of the whatsit, and appends it to the current
3672    list.
3673
3674    A |whatsit_node| is a wild card reserved for extensions to \TEX. The |subtype| field in its
3675    first word says what |whatsit| it is, and implicitly determines the node size (which must be
3676    2 or more) and the format of the remaining words. When a |whatsit_node| is encountered in a
3677    list, special actions are invoked; knowledgeable people who are careful not to mess up the
3678    rest of \TEX\ are able to make \TEX\ do new things by adding code at the end of the program.
3679    For example, there might be a \quote {\TEX nicolor} extension to specify different colors of
3680    ink, and the whatsit node might contain the desired parameters.
3681
3682    The present implementation of \TEX\ treats the features associated with |\write| and |\special|
3683    as if they were extensions, in order to illustrate how such routines might be coded. We shall
3684    defer further discussion of extensions until the end of this program.
3685
3686    However, in \LUAMETATEX\ we only have a generic whatsit node, a small one that can be used to
3687    implement whatever you like, using \LUA. So, all we have here is the above comment as
3688    guideline for that.
3689
3690    \TEX\ makes use of the fact that |hlist_node|, |vlist_node|, |rule_node|, |insert_node|,
3691    |mark_node|, |adjust_node|, |disc_node|, |whatsit_node|, and |math_node| are at the low end of
3692    the type codes, by permitting a break at glue in a list if and only if the |type| of the
3693    previous node is less than |math_node|. Furthermore, a node is discarded after a break if its
3694    type is |math_node| or~more.
3695
3696    A |glue_node| represents glue in a list. However, it is really only a pointer to a separate
3697    glue specification, since \TEX\ makes use of the fact that many essentially identical nodes of
3698    glue are usually present. If |p| points to a |glue_node|, |glue_ptr(p)| points to another packet
3699    of words that specify the stretch and shrink components, etc.
3700
3701    Glue nodes also serve to represent leaders; the |subtype| is used to distinguish between
3702    ordinary glue (which is called |normal|) and the three kinds of leaders (which are called
3703    |a_leaders|, |c_leaders|, and |x_leaders|). The |leader_ptr| field points to a rule node or to
3704    a box node containing the leaders; it is set to |null| in ordinary glue nodes.
3705
3706    Many kinds of glue are computed from \TEX's skip parameters, and it is helpful to know which
3707    parameter has led to a particular glue node. Therefore the |subtype| is set to indicate the
3708    source of glue, whenever it originated as a parameter. We will be defining symbolic names for
3709    the parameter numbers later (e.g., |line_skip_code = 0|, |baseline_skip_code = 1|, etc.); it
3710    suffices for now to say that the |subtype| of parametric glue will be the same as the parameter
3711    number, plus~one.
3712
3713    In math formulas there are two more possibilities for the |subtype| in a glue node: |mu_glue|
3714    denotes an |\mskip| (where the units are scaled |mu| instead of scaled |pt|); and
3715    |cond_math_glue| denotes the |\nonscript| feature that cancels the glue node immediately
3716    following if it appears in a subscript.
3717
3718    A glue specification has a halfword reference count in its first word, representing |null|
3719    plus the number of glue nodes that point to it (less one). Note that the reference count
3720    appears in the same position as the |link| field in list nodes; this is the field that is
3721    initialized to |null| when a node is allocated, and it is also the field that is flagged by
3722    |empty_flag| in empty nodes.
3723
3724    Glue specifications also contain three |scaled| fields, for the |width|, |stretch|, and
3725    |shrink| dimensions. Finally, there are two one-byte fields called |stretch_order| and
3726    |shrink_order|; these contain the orders of infinity (|normal|, |sfi|, |fil|, |fill|, or
3727    |filll|) corresponding to the stretch and shrink values.
3728
3729    Here is a function that returns a pointer to a copy of a glue spec. The reference count in the
3730    copy is |null|, because there is assumed to be exactly one reference to the new specification.
3731
3732*/
3733
3734halfword tex_new_glue_spec_node(halfword q)
3735{
3736    if (q) {
3737        switch (node_type(q)) {
3738            case glue_spec_node:
3739                return tex_copy_node(q);
3740            case glue_node:
3741                {
3742                    halfword p = tex_copy_node(zero_glue);
3743                    glue_amount(p) = glue_amount(q);
3744                    glue_stretch(p) = glue_stretch(q);
3745                    glue_shrink(p) = glue_shrink(q);
3746                    glue_stretch_order(p) = glue_stretch_order(q);
3747                    glue_shrink_order(p) = glue_shrink_order(q);
3748                    return p;
3749                }
3750        }
3751    }
3752    return tex_copy_node(zero_glue);
3753}
3754
3755/*tex
3756
3757    And here's a function that creates a glue node for a given parameter identified by its code
3758    number; for example, |new_param_glue(line_skip_code)| returns a pointer to a glue node for the
3759    current |\lineskip|.
3760
3761*/
3762
3763halfword tex_new_param_glue_node(quarterword p, quarterword s)
3764{
3765    halfword n = tex_new_node(glue_node, s);
3766    halfword g = glue_parameter(p);
3767    if (g) {
3768        memcpy((void *) (lmt_node_memory_state.nodes + n + 2), (void *) (lmt_node_memory_state.nodes + g + 2), (glue_spec_size - 2) * (sizeof(memoryword)));
3769    }
3770    return n;
3771}
3772
3773/*tex
3774
3775    Glue nodes that are more or less anonymous are created by |new_glue|, whose argument points to
3776    a glue specification.
3777
3778*/
3779
3780halfword tex_new_glue_node(halfword q, quarterword s)
3781{
3782    halfword p = tex_new_node(glue_node, s);
3783    memcpy((void *) (lmt_node_memory_state.nodes + p + 2), (void *) (lmt_node_memory_state.nodes + q + 2), (glue_spec_size - 2) * (sizeof(memoryword)));
3784    return p;
3785}
3786
3787/*tex
3788
3789    Still another subroutine is needed: |new_skip_param|. This one is sort of a combination of
3790    |new_param_glue| and |new_glue|. It creates a glue node for one of the current glue parameters,
3791    but it makes a fresh copy of the glue specification, since that specification will probably be
3792    subject to change, while the parameter will stay put.
3793
3794    Remark: as we have copies we don't need this one can use |new_param_glue| instead.
3795
3796*/
3797
3798/*tex
3799
3800    A |kern_node| has a |width| field to specify a (normally negative) amount of spacing. This
3801    spacing correction appears in horizontal lists between letters like A and V when the font
3802    designer said that it looks better to move them closer together or further apart. A kern node
3803    can also appear in a vertical list, when its |width| denotes additional spacing in the vertical
3804    direction. The |subtype| is either |normal| (for kerns inserted from font information or math
3805    mode calculations) or |explicit| (for kerns inserted from |\kern| and |\/| commands) or
3806    |acc_kern| (for kerns inserted from non-math accents) or |mu_glue| (for kerns inserted from
3807    |\mkern| specifications in math formulas).
3808
3809    The |new_kern| function creates a (font) kern node having a given width.
3810
3811*/
3812
3813halfword tex_new_kern_node(scaled w, quarterword s)
3814{
3815    halfword p = tex_new_node(kern_node, s);
3816    kern_amount(p) = w;
3817    return p;
3818}
3819
3820/*tex
3821
3822    A |penalty_node| specifies the penalty associated with line or page breaking, in its |penalty|
3823    field. This field is a fullword integer, but the full range of integer values is not used:
3824    Any penalty |>=10000| is treated as infinity, and no break will be allowed for such high values.
3825    Similarly, any penalty |<= -10000| is treated as negative infinity, and a break will be forced.
3826
3827    Anyone who has been reading the last few sections of the program will be able to guess what
3828    comes next.
3829
3830*/
3831
3832halfword tex_new_penalty_node(halfword m, quarterword s)
3833{
3834    halfword p = tex_new_node(penalty_node, s);
3835    penalty_amount(p) = m;
3836    return p;
3837}
3838
3839/*tex
3840
3841    You might think that we have introduced enough node types by now. Well, almost, but there is
3842    one more: An |unset_node| has nearly the same format as an |hlist_node| or |vlist_node|; it is
3843    used for entries in |\halign| or |\valign| that are not yet in their final form, since the box
3844    dimensions are their \quote {natural} sizes before any glue adjustment has been made. The
3845    |glue_set| word is not present; instead, we have a |glue_stretch| field, which contains the
3846    total stretch of order |glue_order| that is present in the hlist or vlist being boxed.
3847    Similarly, the |shift_amount| field is replaced by a |glue_shrink| field, containing the total
3848    shrink of order |glue_sign| that is present. The |subtype| field is called |span_count|; an
3849    unset box typically contains the data for |qo(span_count)+1| columns. Unset nodes will be
3850    changed to box nodes when alignment is completed.
3851
3852    In fact, there are still more types coming. When we get to math formula processing we will
3853    see that a |style_node| has |type=14|; and a number of larger type codes will also be defined,
3854    for use in math mode only.
3855
3856    Warning: If any changes are made to these data structure layouts, such as changing any of the
3857    node sizes or even reordering the words of nodes, the |copy_node_list| procedure and the memory
3858    initialization code below may have to be changed. However, other references to the nodes are
3859    made symbolically in terms of the \WEB\ macro definitions above, so that format changes will
3860    leave \TEX's other algorithms intact.
3861
3862    Some day we might store the current paragraph properties in this node. Actually, we already
3863    store the interline and broken penalties. But it then also demands adaptation if the functions
3864    that deal with breaking (we can just pass the local par node) and related specification node
3865    cleanups. We could either snapshot parameters before a group ends, or we can add a lots of
3866    |\local...| parameters.
3867
3868    This section might move to its own file. 
3869
3870*/
3871
3872halfword tex_new_par_node(quarterword subtype)
3873{
3874    int callback_id, top;
3875    halfword p = tex_new_node(par_node, subtype);
3876    /* */
3877    if (subtype == parameter_par_subtype) {
3878        tex_set_local_interline_penalty(p, local_interline_penalty_par);
3879        tex_set_local_broken_penalty(p, local_broken_penalty_par);
3880        tex_set_local_tolerance(p, local_tolerance_par);
3881        tex_set_local_pre_tolerance(p, local_pre_tolerance_par);
3882    }
3883    par_dir(p) = par_direction_par;
3884    /* */
3885    tex_add_local_boxes(p);
3886    if (subtype != local_box_par_subtype) {
3887        /*tex Callback with node passed. Todo: move to luanode with the rest of callbacks. */
3888        callback_id = lmt_callback_defined(insert_par_callback);
3889        if (callback_id > 0) {
3890            lua_State *L = lmt_lua_state.lua_instance;
3891            if (lmt_callback_okay(L, callback_id, &top)) {
3892                int i;
3893                lmt_node_list_to_lua(L, p);
3894                lmt_push_par_mode(L, subtype);
3895                i = lmt_callback_call(L, 2, 0 ,top);
3896                if (i) {
3897                    lmt_callback_error(L, top, i);
3898                } else {
3899                    lmt_callback_wrapup(L, top);
3900                }
3901            }
3902        }
3903    }
3904    return p;
3905}
3906
3907static halfword tex_aux_internal_to_par_code(halfword cmd, halfword index) {
3908    switch (cmd) {
3909        case internal_integer_cmd:
3910            switch (index) {
3911                case hang_after_code             : return par_hang_after_code;
3912                case adjust_spacing_code         : return par_adjust_spacing_code;
3913                case protrude_chars_code         : return par_protrude_chars_code;
3914                case pre_tolerance_code          : return par_pre_tolerance_code;
3915                case tolerance_code              : return par_tolerance_code;
3916                case looseness_code              : return par_looseness_code;
3917                case last_line_fit_code          : return par_last_line_fit_code;
3918                case line_penalty_code           : return par_line_penalty_code;
3919                case inter_line_penalty_code     : return par_inter_line_penalty_code;
3920                case club_penalty_code           : return par_club_penalty_code;
3921                case widow_penalty_code          : return par_widow_penalty_code;
3922                case display_widow_penalty_code  : return par_display_widow_penalty_code;
3923                case orphan_penalty_code         : return par_orphan_penalty_code;
3924                case single_line_penalty_code    : return par_single_line_penalty_code;
3925                case broken_penalty_code         : return par_broken_penalty_code;
3926                case adj_demerits_code           : return par_adj_demerits_code;
3927                case double_adj_demerits_code    : return par_double_adj_demerits_code;
3928                case double_hyphen_demerits_code : return par_double_hyphen_demerits_code;
3929                case final_hyphen_demerits_code  : return par_final_hyphen_demerits_code;
3930                case shaping_penalties_mode_code : return par_shaping_penalties_mode_code;
3931                case shaping_penalty_code        : return par_shaping_penalty_code;
3932            }
3933            break;
3934        case internal_dimension_cmd:
3935            switch (index) {
3936                case hsize_code                   : return par_hsize_code;
3937                case hang_indent_code             : return par_hang_indent_code;
3938                case par_indent_code              : return par_par_indent_code;
3939                case emergency_stretch_code       : return par_emergency_stretch_code;
3940                case line_skip_limit_code         : return par_line_skip_limit_code;
3941                case emergency_extra_stretch_code : return par_emergency_extra_stretch_code;
3942            }
3943            break;
3944        case internal_glue_cmd:
3945            switch (index) {
3946                case left_skip_code              : return par_left_skip_code;
3947                case right_skip_code             : return par_right_skip_code;
3948                case par_fill_left_skip_code     : return par_par_fill_left_skip_code;
3949                case par_fill_right_skip_code    : return par_par_fill_right_skip_code;
3950                case par_init_left_skip_code     : return par_par_init_left_skip_code;
3951                case par_init_right_skip_code    : return par_par_init_right_skip_code;
3952                case emergency_left_skip_code    : return par_emergency_left_skip_code;
3953                case emergency_right_skip_code   : return par_emergency_right_skip_code;
3954                case baseline_skip_code          : return par_baseline_skip_code;
3955                case line_skip_code              : return par_line_skip_code;
3956            }
3957            break;
3958        case specification_reference_cmd:
3959            switch (index) {
3960                case par_shape_code              : return par_par_shape_code;
3961                case inter_line_penalties_code   : return par_inter_line_penalties_code;
3962                case club_penalties_code         : return par_club_penalties_code;
3963                case widow_penalties_code        : return par_widow_penalties_code;
3964                case display_widow_penalties_code: return par_display_widow_penalties_code;
3965                case orphan_penalties_code       : return par_orphan_penalties_code;
3966                case par_passes_code             : return par_par_passes_code;
3967            }
3968            break;
3969    }
3970    return -1;
3971}
3972
3973void tex_update_par_par(halfword cmd, halfword index)
3974{
3975    halfword code = tex_aux_internal_to_par_code(cmd, index);
3976    if (code >= 0) {
3977        halfword par = tex_find_par_par(cur_list.head);
3978        if (par) {
3979            tex_snapshot_par(par, code);
3980        }
3981    }
3982}
3983
3984halfword tex_get_par_par(halfword p, halfword what)
3985{
3986    int set = tex_par_state_is_set(p, what);
3987    switch (what) {
3988        case par_par_shape_code:               return set ? par_par_shape(p)               : par_shape_par;
3989        case par_inter_line_penalties_code:    return set ? par_inter_line_penalties(p)    : inter_line_penalties_par;
3990        case par_club_penalties_code:          return set ? par_club_penalties(p)          : club_penalties_par;
3991        case par_widow_penalties_code:         return set ? par_widow_penalties(p)         : widow_penalties_par;
3992        case par_display_widow_penalties_code: return set ? par_display_widow_penalties(p) : display_widow_penalties_par;
3993        case par_orphan_penalties_code:        return set ? par_orphan_penalties(p)        : orphan_penalties_par;
3994        case par_hang_indent_code:             return set ? par_hang_indent(p)             : hang_indent_par;
3995        case par_hang_after_code:              return set ? par_hang_after(p)              : hang_after_par;
3996        case par_hsize_code:                   return set ? par_hsize(p)                   : hsize_par;
3997        case par_left_skip_code:               return set ? par_left_skip(p)               : left_skip_par;
3998        case par_right_skip_code:              return set ? par_right_skip(p)              : right_skip_par;
3999        case par_last_line_fit_code:           return set ? par_last_line_fit(p)           : last_line_fit_par;
4000        case par_pre_tolerance_code:           return set ? par_pre_tolerance(p)           : pre_tolerance_par;
4001        case par_tolerance_code:               return set ? par_tolerance(p)               : tolerance_par;
4002        case par_looseness_code:               return set ? par_looseness(p)               : looseness_par;
4003        case par_adjust_spacing_code:          return set ? par_adjust_spacing(p)          : adjust_spacing_par;
4004        case par_adj_demerits_code:            return set ? par_adj_demerits(p)            : adj_demerits_par;
4005        case par_double_adj_demerits_code:     return set ? par_double_adj_demerits(p)     : double_adj_demerits_par;
4006        case par_protrude_chars_code:          return set ? par_protrude_chars(p)          : protrude_chars_par;
4007        case par_line_penalty_code:            return set ? par_line_penalty(p)            : line_penalty_par;
4008        case par_double_hyphen_demerits_code:  return set ? par_double_hyphen_demerits(p)  : double_hyphen_demerits_par;
4009        case par_final_hyphen_demerits_code:   return set ? par_final_hyphen_demerits(p)   : final_hyphen_demerits_par;
4010        case par_inter_line_penalty_code:      return set ? par_inter_line_penalty(p)      : inter_line_penalty_par;
4011        case par_club_penalty_code:            return set ? par_club_penalty(p)            : club_penalty_par;
4012        case par_widow_penalty_code:           return set ? par_widow_penalty(p)           : widow_penalty_par;
4013        case par_display_widow_penalty_code:   return set ? par_display_widow_penalty(p)   : display_widow_penalty_par;
4014        case par_orphan_penalty_code:          return set ? par_orphan_penalty(p)          : orphan_penalty_par;
4015        case par_single_line_penalty_code:     return set ? par_single_line_penalty(p)     : single_line_penalty_par;
4016        case par_broken_penalty_code:          return set ? par_broken_penalty(p)          : broken_penalty_par;
4017        case par_emergency_stretch_code:       return set ? par_emergency_stretch(p)       : emergency_stretch_par;
4018        case par_par_indent_code:              return set ? par_par_indent(p)              : par_indent_par;
4019        case par_par_fill_left_skip_code:      return set ? par_par_fill_left_skip(p)      : par_fill_left_skip_par;
4020        case par_par_fill_right_skip_code:     return set ? par_par_fill_right_skip(p)     : par_fill_right_skip_par;
4021        case par_par_init_left_skip_code:      return set ? par_par_init_left_skip(p)      : par_init_left_skip_par;
4022        case par_par_init_right_skip_code:     return set ? par_par_init_right_skip(p)     : par_init_right_skip_par;
4023        case par_emergency_left_skip_code:     return set ? par_emergency_left_skip(p)     : emergency_left_skip_par;
4024        case par_emergency_right_skip_code:    return set ? par_emergency_right_skip(p)    : emergency_right_skip_par;
4025        case par_baseline_skip_code:           return set ? par_baseline_skip(p)           : baseline_skip_par;
4026        case par_line_skip_code:               return set ? par_line_skip(p)               : line_skip_par;
4027        case par_line_skip_limit_code:         return set ? par_line_skip_limit(p)         : line_skip_limit_par;
4028        case par_adjust_spacing_step_code:     return set ? par_adjust_spacing_step(p)     : adjust_spacing_step_par;
4029        case par_adjust_spacing_shrink_code:   return set ? par_adjust_spacing_shrink(p)   : adjust_spacing_shrink_par;
4030        case par_adjust_spacing_stretch_code:  return set ? par_adjust_spacing_stretch(p)  : adjust_spacing_stretch_par;
4031        case par_hyphenation_mode_code:        return set ? par_hyphenation_mode(p)        : hyphenation_mode_par;
4032        case par_shaping_penalties_mode_code:  return set ? par_shaping_penalties_mode(p)  : shaping_penalties_mode_par;
4033        case par_shaping_penalty_code:         return set ? par_shaping_penalty(p)         : shaping_penalty_par;
4034        case par_emergency_extra_stretch_code: return set ? par_emergency_extra_stretch(p) : emergency_extra_stretch_par;
4035        case par_par_passes_code:              return set ? par_par_passes(p)              : par_passes_par;
4036    }
4037    return null;
4038}
4039
4040void tex_set_par_par(halfword p, halfword what, halfword v, int force)
4041{
4042    if (force || tex_par_state_is_set(p, what)) {
4043        switch (what) {
4044            case par_hsize_code:
4045                par_hsize(p) = v;
4046                break;
4047            case par_left_skip_code:
4048                if (par_left_skip(p)) {
4049                    tex_flush_node(par_left_skip(p));
4050                }
4051                par_left_skip(p) = v ? tex_copy_node(v) : null;
4052                break;
4053            case par_right_skip_code:
4054                if (par_right_skip(p)) {
4055                    tex_flush_node(par_right_skip(p));
4056                }
4057                par_right_skip(p) = v ? tex_copy_node(v) : null;
4058                break;
4059            case par_hang_indent_code:
4060                par_hang_indent(p) = v;
4061                break;
4062            case par_hang_after_code:
4063                par_hang_after(p) = v;
4064                break;
4065            case par_par_indent_code:
4066                par_par_indent(p) = v;
4067                break;
4068            case par_par_fill_left_skip_code:
4069                if (par_par_fill_left_skip(p)) {
4070                    tex_flush_node(par_par_fill_left_skip(p));
4071                }
4072                par_par_fill_left_skip(p) = v ? tex_copy_node(v) : null;
4073                break;
4074            case par_par_fill_right_skip_code:
4075                if (par_par_fill_right_skip(p)) {
4076                    tex_flush_node(par_par_fill_right_skip(p));
4077                }
4078                par_par_fill_right_skip(p) = v ? tex_copy_node(v) : null;
4079                break;
4080            case par_par_init_left_skip_code:
4081                if (par_par_init_left_skip(p)) {
4082                    tex_flush_node(par_par_init_left_skip(p));
4083                }
4084                par_par_init_left_skip(p) = v ? tex_copy_node(v) : null;
4085                break;
4086            case par_par_init_right_skip_code:
4087                if (par_par_init_right_skip(p)) {
4088                    tex_flush_node(par_par_init_right_skip(p));
4089                }
4090                par_par_init_right_skip(p) = v ? tex_copy_node(v) : null;
4091                break;
4092            case par_emergency_left_skip_code:
4093                if (par_emergency_left_skip(p)) {
4094                    tex_flush_node(par_emergency_left_skip(p));
4095                }
4096                par_emergency_left_skip(p) = v ? tex_copy_node(v) : null;
4097                break;
4098            case par_emergency_right_skip_code:
4099                if (par_emergency_right_skip(p)) {
4100                    tex_flush_node(par_emergency_right_skip(p));
4101                }
4102                par_emergency_right_skip(p) = v ? tex_copy_node(v) : null;
4103                break;
4104            case par_adjust_spacing_code:
4105                par_adjust_spacing(p) = v;
4106                break;
4107            case par_protrude_chars_code:
4108                par_protrude_chars(p) = v;
4109                break;
4110            case par_pre_tolerance_code:
4111                par_pre_tolerance(p) = v;
4112                break;
4113            case par_tolerance_code:
4114                par_tolerance(p) = v;
4115                break;
4116            case par_emergency_stretch_code:
4117                par_emergency_stretch(p) = v;
4118                break;
4119            case par_looseness_code:
4120                par_looseness(p) = v;
4121                break;
4122            case par_single_line_penalty_code:
4123                par_single_line_penalty(p) = v;
4124                break;
4125            case par_last_line_fit_code:
4126                par_last_line_fit(p) = v;
4127                break;
4128            case par_line_penalty_code:
4129                par_line_penalty(p) = v;
4130                break;
4131            case par_inter_line_penalty_code:
4132                par_inter_line_penalty(p) = v;
4133                break;
4134            case par_club_penalty_code:
4135                par_club_penalty(p) = v;
4136                break;
4137            case par_widow_penalty_code:
4138                par_widow_penalty(p) = v;
4139                break;
4140            case par_display_widow_penalty_code:
4141                par_display_widow_penalty(p) = v;
4142                break;
4143            case par_orphan_penalty_code:
4144                par_orphan_penalty(p) = v;
4145                break;
4146            case par_broken_penalty_code:
4147                par_broken_penalty(p) = v;
4148                break;
4149            case par_adj_demerits_code:
4150                par_adj_demerits(p) = v;
4151                break;
4152            case par_double_adj_demerits_code:
4153                par_double_adj_demerits(p) = v;
4154                break;
4155            case par_double_hyphen_demerits_code:
4156                par_double_hyphen_demerits(p) = v;
4157                break;
4158            case par_final_hyphen_demerits_code:
4159                par_final_hyphen_demerits(p) = v;
4160                break;
4161            case par_par_shape_code:
4162                if (par_par_shape(p)) {
4163                    tex_flush_node(par_par_shape(p));
4164                }
4165                par_par_shape(p) = v ? tex_copy_node(v) : null;
4166                break;
4167            case par_inter_line_penalties_code:
4168                if (par_inter_line_penalties(p)) {
4169                    tex_flush_node(par_inter_line_penalties(p));
4170                }
4171                par_inter_line_penalties(p) = v ? tex_copy_node(v) : null;
4172                break;
4173            case par_club_penalties_code:
4174                if (par_club_penalties(p)) {
4175                    tex_flush_node(par_club_penalties(p));
4176                }
4177                par_club_penalties(p) = v ? tex_copy_node(v) : null;
4178                break;
4179            case par_widow_penalties_code:
4180                if (par_widow_penalties(p)) {
4181                    tex_flush_node(par_widow_penalties(p));
4182                }
4183                par_widow_penalties(p) = v ? tex_copy_node(v) : null;
4184                break;
4185            case par_display_widow_penalties_code:
4186                if (par_display_widow_penalties(p)) {
4187                    tex_flush_node(par_display_widow_penalties(p));
4188                }
4189                par_display_widow_penalties(p) = v ? tex_copy_node(v) : null;
4190                break;
4191            case par_orphan_penalties_code:
4192                if (par_orphan_penalties(p)) {
4193                    tex_flush_node(par_orphan_penalties(p));
4194                }
4195                par_orphan_penalties(p) = v ? tex_copy_node(v) : null;
4196                break;
4197            case par_baseline_skip_code:
4198                if (par_baseline_skip(p)) {
4199                    tex_flush_node(par_baseline_skip(p));
4200                }
4201                par_baseline_skip(p) = v ? tex_copy_node(v) : null;
4202                break;
4203            case par_line_skip_code:
4204                if (par_line_skip(p)) {
4205                    tex_flush_node(par_line_skip(p));
4206                }
4207                par_line_skip(p) = v ? tex_copy_node(v) : null;
4208                break;
4209            case par_line_skip_limit_code:
4210                par_line_skip_limit(p) = v;
4211                break;
4212            case par_adjust_spacing_step_code:
4213                par_adjust_spacing_step(p) = v;
4214                break;
4215            case par_adjust_spacing_shrink_code:
4216                par_adjust_spacing_shrink(p) = v;
4217                break;
4218            case par_adjust_spacing_stretch_code:
4219                par_adjust_spacing_stretch(p) = v;
4220                break;
4221            case par_hyphenation_mode_code:
4222                par_hyphenation_mode(p) = v;
4223                break;
4224            case par_shaping_penalties_mode_code:
4225                par_shaping_penalties_mode(p) = v;
4226                break;
4227            case par_shaping_penalty_code:
4228                par_shaping_penalty(p) = v;
4229                break;
4230            case par_emergency_extra_stretch_code:
4231                par_emergency_extra_stretch(p) = v;
4232                break;
4233            case par_par_passes_code:
4234                if (par_par_passes(p)) {
4235                    tex_flush_node(par_par_passes(p));
4236                }
4237                par_par_passes(p) = v ? tex_copy_node(v) : null;
4238                break;
4239        }
4240        tex_set_par_state(p, what);
4241    }
4242}
4243
4244/* 
4245    This is the reference but as it's called often we use an inlined variant with less redudant
4246    testing and branching. 
4247*/
4248
4249/*
4250    void tex_snapshot_par(halfword p, halfword what)
4251    {
4252        if (p && lmt_main_state.run_state != initializing_state) {
4253            int unset = 0;
4254            if (what) {
4255                if (what < 0) {
4256                    unset = 1;
4257                    what = -what;
4258                }
4259                if (what > par_all_category) {
4260                    what = par_all_category;
4261                }
4262            } else {
4263                unset = 1;
4264                what = par_all_category;
4265            }
4266            if (tex_par_to_be_set(what, par_hsize_code))                   { tex_set_par_par(p, par_hsize_code,                   unset ? null : hsize_par,                   1); }
4267            if (tex_par_to_be_set(what, par_left_skip_code))               { tex_set_par_par(p, par_left_skip_code,               unset ? null : left_skip_par,               1); }
4268            if (tex_par_to_be_set(what, par_right_skip_code))              { tex_set_par_par(p, par_right_skip_code,              unset ? null : right_skip_par,              1); }
4269            if (tex_par_to_be_set(what, par_hang_indent_code))             { tex_set_par_par(p, par_hang_indent_code,             unset ? null : hang_indent_par,             1); }
4270            if (tex_par_to_be_set(what, par_hang_after_code))              { tex_set_par_par(p, par_hang_after_code,              unset ? null : hang_after_par,              1); }
4271            if (tex_par_to_be_set(what, par_par_indent_code))              { tex_set_par_par(p, par_par_indent_code,              unset ? null : par_indent_par,              1); }
4272            if (tex_par_to_be_set(what, par_par_fill_left_skip_code))      { tex_set_par_par(p, par_par_fill_left_skip_code,      unset ? null : par_fill_left_skip_par,      1); }
4273            if (tex_par_to_be_set(what, par_par_fill_right_skip_code))     { tex_set_par_par(p, par_par_fill_right_skip_code,     unset ? null : par_fill_right_skip_par,     1); }
4274            if (tex_par_to_be_set(what, par_par_init_left_skip_code))      { tex_set_par_par(p, par_par_init_left_skip_code,      unset ? null : par_init_left_skip_par,      1); }
4275            if (tex_par_to_be_set(what, par_par_init_right_skip_code))     { tex_set_par_par(p, par_par_init_right_skip_code,     unset ? null : par_init_right_skip_par,     1); }
4276            if (tex_par_to_be_set(what, par_adjust_spacing_code))          { tex_set_par_par(p, par_adjust_spacing_code,          unset ? null : adjust_spacing_par,          1); }
4277            if (tex_par_to_be_set(what, par_protrude_chars_code))          { tex_set_par_par(p, par_protrude_chars_code,          unset ? null : protrude_chars_par,          1); }
4278            if (tex_par_to_be_set(what, par_pre_tolerance_code))           { tex_set_par_par(p, par_pre_tolerance_code,           unset ? null : pre_tolerance_par,           1); }
4279            if (tex_par_to_be_set(what, par_tolerance_code))               { tex_set_par_par(p, par_tolerance_code,               unset ? null : tolerance_par,               1); }
4280            if (tex_par_to_be_set(what, par_emergency_stretch_code))       { tex_set_par_par(p, par_emergency_stretch_code,       unset ? null : emergency_stretch_par,       1); }
4281            if (tex_par_to_be_set(what, par_looseness_code))               { tex_set_par_par(p, par_looseness_code,               unset ? null : looseness_par,               1); }
4282            if (tex_par_to_be_set(what, par_last_line_fit_code))           { tex_set_par_par(p, par_last_line_fit_code,           unset ? null : last_line_fit_par,           1); }
4283            if (tex_par_to_be_set(what, par_line_penalty_code))            { tex_set_par_par(p, par_line_penalty_code,            unset ? null : line_penalty_par,            1); }
4284            if (tex_par_to_be_set(what, par_inter_line_penalty_code))      { tex_set_par_par(p, par_inter_line_penalty_code,      unset ? null : inter_line_penalty_par,      1); }
4285            if (tex_par_to_be_set(what, par_club_penalty_code))            { tex_set_par_par(p, par_club_penalty_code,            unset ? null : club_penalty_par,            1); }
4286            if (tex_par_to_be_set(what, par_widow_penalty_code))           { tex_set_par_par(p, par_widow_penalty_code,           unset ? null : widow_penalty_par,           1); }
4287            if (tex_par_to_be_set(what, par_display_widow_penalty_code))   { tex_set_par_par(p, par_display_widow_penalty_code,   unset ? null : display_widow_penalty_par,   1); }
4288            if (tex_par_to_be_set(what, par_orphan_penalty_code))          { tex_set_par_par(p, par_orphan_penalty_code,          unset ? null : orphan_penalty_par,          1); }
4289            if (tex_par_to_be_set(what, par_broken_penalty_code))          { tex_set_par_par(p, par_broken_penalty_code,          unset ? null : broken_penalty_par,          1); }
4290            if (tex_par_to_be_set(what, par_adj_demerits_code))            { tex_set_par_par(p, par_adj_demerits_code,            unset ? null : adj_demerits_par,            1); }
4291            if (tex_par_to_be_set(what, par_double_adj_demerits_code))     { tex_set_par_par(p, par_double_adj_demerits_code,     unset ? null : double_adj_demerits_par,     1); }
4292            if (tex_par_to_be_set(what, par_double_hyphen_demerits_code))  { tex_set_par_par(p, par_double_hyphen_demerits_code,  unset ? null : double_hyphen_demerits_par,  1); }
4293            if (tex_par_to_be_set(what, par_final_hyphen_demerits_code))   { tex_set_par_par(p, par_final_hyphen_demerits_code,   unset ? null : final_hyphen_demerits_par,   1); }
4294            if (tex_par_to_be_set(what, par_par_shape_code))               { tex_set_par_par(p, par_par_shape_code,               unset ? null : par_shape_par,               1); }
4295            if (tex_par_to_be_set(what, par_inter_line_penalties_code))    { tex_set_par_par(p, par_inter_line_penalties_code,    unset ? null : inter_line_penalties_par,    1); }
4296            if (tex_par_to_be_set(what, par_club_penalties_code))          { tex_set_par_par(p, par_club_penalties_code,          unset ? null : club_penalties_par,          1); }
4297            if (tex_par_to_be_set(what, par_widow_penalties_code))         { tex_set_par_par(p, par_widow_penalties_code,         unset ? null : widow_penalties_par,         1); }
4298            if (tex_par_to_be_set(what, par_display_widow_penalties_code)) { tex_set_par_par(p, par_display_widow_penalties_code, unset ? null : display_widow_penalties_par, 1); }
4299            if (tex_par_to_be_set(what, par_orphan_penalties_code))        { tex_set_par_par(p, par_orphan_penalties_code,        unset ? null : orphan_penalties_par,        1); }
4300            if (tex_par_to_be_set(what, par_baseline_skip_code))           { tex_set_par_par(p, par_baseline_skip_code,           unset ? null : baseline_skip_par,           1); }
4301            if (tex_par_to_be_set(what, par_line_skip_code))               { tex_set_par_par(p, par_line_skip_code,               unset ? null : line_skip_par,               1); }
4302            if (tex_par_to_be_set(what, par_line_skip_limit_code))         { tex_set_par_par(p, par_line_skip_limit_code,         unset ? null : line_skip_limit_par,         1); }
4303            if (tex_par_to_be_set(what, par_adjust_spacing_step_code))     { tex_set_par_par(p, par_adjust_spacing_step_code,     unset ? null : adjust_spacing_step_par,     1); }
4304            if (tex_par_to_be_set(what, par_adjust_spacing_shrink_code))   { tex_set_par_par(p, par_adjust_spacing_shrink_code,   unset ? null : adjust_spacing_shrink_par,   1); }
4305            if (tex_par_to_be_set(what, par_adjust_spacing_stretch_code))  { tex_set_par_par(p, par_adjust_spacing_stretch_code,  unset ? null : adjust_spacing_stretch_par,  1); }
4306            if (tex_par_to_be_set(what, par_hyphenation_mode_code))        { tex_set_par_par(p, par_hyphenation_mode_code,        unset ? null : hyphenation_mode_par,        1); }
4307            if (tex_par_to_be_set(what, par_shaping_penalties_mode_code))  { tex_set_par_par(p, par_shaping_penalties_mode_code,  unset ? null : shaping_penalties_mode_par,  1); }
4308            if (tex_par_to_be_set(what, par_shaping_penalty_code))         { tex_set_par_par(p, par_shaping_penalty_code,         unset ? null : shaping_penalty_par,         1); }
4309    
4310            if (what == par_all_category) {
4311                par_state(p) = unset ? 0 : par_all_category;
4312            } else if (unset) {
4313                par_state(p) &= ~(what | par_state(p));
4314            } else {
4315                par_state(p) |= what;
4316            }
4317        }
4318    }
4319*/
4320
4321void tex_snapshot_par(halfword p, halfword what)
4322{
4323    if (p && lmt_main_state.run_state != initializing_state) {
4324        int unset = 0;
4325        if (what) {
4326            if (what < 0) {
4327                unset = 1;
4328                what = -what;
4329            }
4330            if (what > par_all_category) {
4331                what = par_all_category;
4332            }
4333        } else {
4334            unset = 1;
4335            what = par_all_category;
4336        }
4337        if (tex_par_to_be_set(what, par_hsize_code)) { 
4338             par_hsize(p) = unset ? null : hsize_par; 
4339        }
4340        if (tex_par_to_be_set(what, par_left_skip_code)) { 
4341            halfword v = unset ? null : left_skip_par;
4342            if (par_left_skip(p)) {
4343                tex_flush_node(par_left_skip(p));
4344            }
4345            par_left_skip(p) = v ? tex_copy_node(v) : null;
4346        }
4347        if (tex_par_to_be_set(what, par_right_skip_code)) { 
4348            halfword v = unset ? null : right_skip_par; 
4349            if (par_right_skip(p)) {
4350                tex_flush_node(par_right_skip(p));
4351            }
4352            par_right_skip(p) = v ? tex_copy_node(v) : null;
4353        }
4354        if (tex_par_to_be_set(what, par_hang_indent_code)) { 
4355            par_hang_indent(p) = unset ? null : hang_indent_par; 
4356        }
4357        if (tex_par_to_be_set(what, par_hang_after_code)) { 
4358            par_hang_after(p) = unset ? null : hang_after_par; 
4359        }
4360        if (tex_par_to_be_set(what, par_par_indent_code)) { 
4361            par_par_indent(p) = unset ? null : par_indent_par; 
4362        }
4363        if (tex_par_to_be_set(what, par_par_fill_left_skip_code)) { 
4364            halfword v = unset ? null : par_fill_left_skip_par; 
4365            if (par_par_fill_left_skip(p)) {
4366                tex_flush_node(par_par_fill_left_skip(p));
4367            }
4368            par_par_fill_left_skip(p) = v ? tex_copy_node(v) : null;
4369        }
4370        if (tex_par_to_be_set(what, par_par_fill_right_skip_code)) { 
4371            halfword v = unset ? null : par_fill_right_skip_par; 
4372            if (par_par_fill_right_skip(p)) {
4373                tex_flush_node(par_par_fill_right_skip(p));
4374            }
4375            par_par_fill_right_skip(p) = v ? tex_copy_node(v) : null;
4376        }
4377        if (tex_par_to_be_set(what, par_par_init_left_skip_code)) { 
4378            halfword v = unset ? null : par_init_left_skip_par; 
4379            if (par_par_init_left_skip(p)) {
4380                tex_flush_node(par_par_init_left_skip(p));
4381            }
4382            par_par_init_left_skip(p) = v ? tex_copy_node(v) : null;
4383        }
4384        if (tex_par_to_be_set(what, par_par_init_right_skip_code)) { 
4385            halfword v = unset ? null : par_init_right_skip_par; 
4386            if (par_par_init_right_skip(p)) {
4387                tex_flush_node(par_par_init_right_skip(p));
4388            }
4389            par_par_init_right_skip(p) = v ? tex_copy_node(v) : null;
4390        }
4391        if (tex_par_to_be_set(what, par_emergency_left_skip_code)) { 
4392            halfword v = unset ? null : emergency_left_skip_par; 
4393            if (par_emergency_left_skip(p)) {
4394                tex_flush_node(par_emergency_left_skip(p));
4395            }
4396            par_emergency_left_skip(p) = v ? tex_copy_node(v) : null;
4397        }
4398        if (tex_par_to_be_set(what, par_emergency_right_skip_code)) { 
4399            halfword v = unset ? null : emergency_right_skip_par; 
4400            if (par_emergency_right_skip(p)) {
4401                tex_flush_node(par_emergency_right_skip(p));
4402            }
4403            par_emergency_right_skip(p) = v ? tex_copy_node(v) : null;
4404        }
4405        if (tex_par_to_be_set(what, par_adjust_spacing_code)) { 
4406            par_adjust_spacing(p) = unset ? null : adjust_spacing_par; 
4407        }
4408        if (tex_par_to_be_set(what, par_protrude_chars_code)) { 
4409            par_protrude_chars(p) = unset ? null : protrude_chars_par; 
4410        }
4411        if (tex_par_to_be_set(what, par_pre_tolerance_code)) { 
4412            par_pre_tolerance(p) = unset ? null : pre_tolerance_par; 
4413        }
4414        if (tex_par_to_be_set(what, par_tolerance_code)) { 
4415            par_tolerance(p) = unset ? null : tolerance_par; 
4416        }
4417        if (tex_par_to_be_set(what, par_emergency_stretch_code)) { 
4418            par_emergency_stretch(p) = unset ? null : emergency_stretch_par; 
4419        }
4420        if (tex_par_to_be_set(what, par_looseness_code)) { 
4421            par_looseness(p) = unset ? null : looseness_par; 
4422        }
4423        if (tex_par_to_be_set(what, par_last_line_fit_code)) { 
4424            par_last_line_fit(p) = unset ? null : last_line_fit_par; 
4425        }
4426        if (tex_par_to_be_set(what, par_line_penalty_code)) { 
4427            par_line_penalty(p) = unset ? null : line_penalty_par; 
4428        }
4429        if (tex_par_to_be_set(what, par_inter_line_penalty_code)) { 
4430            par_inter_line_penalty(p) = unset ? null : inter_line_penalty_par; 
4431        }
4432        if (tex_par_to_be_set(what, par_club_penalty_code)) { 
4433            par_club_penalty(p) = unset ? null : club_penalty_par; 
4434        }
4435        if (tex_par_to_be_set(what, par_widow_penalty_code)) { 
4436            par_widow_penalty(p) = unset ? null : widow_penalty_par; 
4437        }
4438        if (tex_par_to_be_set(what, par_display_widow_penalty_code)) { 
4439            par_display_widow_penalty(p) = unset ? null : display_widow_penalty_par; 
4440        }
4441        if (tex_par_to_be_set(what, par_orphan_penalty_code)) { 
4442            par_orphan_penalty(p) = unset ? null : orphan_penalty_par; 
4443        }
4444        if (tex_par_to_be_set(what, par_single_line_penalty_code)) { 
4445            par_single_line_penalty(p) = unset ? null : single_line_penalty_par; 
4446        }
4447        if (tex_par_to_be_set(what, par_broken_penalty_code)) { 
4448            par_broken_penalty(p) = unset ? null : broken_penalty_par; 
4449        }
4450        if (tex_par_to_be_set(what, par_adj_demerits_code)) { 
4451            par_adj_demerits(p) = unset ? null : adj_demerits_par; 
4452        }
4453        if (tex_par_to_be_set(what, par_double_adj_demerits_code)) { 
4454            par_double_adj_demerits(p) = unset ? null : double_adj_demerits_par; 
4455        }
4456        if (tex_par_to_be_set(what, par_double_hyphen_demerits_code)){ 
4457            par_double_hyphen_demerits(p) = unset ? null : double_hyphen_demerits_par; 
4458        }
4459        if (tex_par_to_be_set(what, par_final_hyphen_demerits_code)) { 
4460            par_final_hyphen_demerits(p) = unset ? null : final_hyphen_demerits_par; 
4461        }
4462        if (tex_par_to_be_set(what, par_par_shape_code))  { 
4463            halfword v = unset ? null : par_shape_par; 
4464            if (par_par_shape(p)) {
4465                tex_flush_node(par_par_shape(p));
4466            }
4467            par_par_shape(p) = v ? tex_copy_node(v) : null;
4468        }
4469        if (tex_par_to_be_set(what, par_inter_line_penalties_code)) { 
4470            halfword v = unset ? null : inter_line_penalties_par; 
4471            if (par_inter_line_penalties(p)) {
4472                tex_flush_node(par_inter_line_penalties(p));
4473            }
4474            par_inter_line_penalties(p) = v ? tex_copy_node(v) : null;
4475        }
4476        if (tex_par_to_be_set(what, par_club_penalties_code)) { 
4477            halfword v = unset ? null : club_penalties_par; 
4478            if (par_club_penalties(p)) {
4479                tex_flush_node(par_club_penalties(p));
4480            }
4481            par_club_penalties(p) = v ? tex_copy_node(v) : null;
4482        }
4483        if (tex_par_to_be_set(what, par_widow_penalties_code)) { 
4484            halfword v = unset ? null : widow_penalties_par; 
4485            if (par_widow_penalties(p)) {
4486                tex_flush_node(par_widow_penalties(p));
4487            }
4488            par_widow_penalties(p) = v ? tex_copy_node(v) : null;
4489        }
4490        if (tex_par_to_be_set(what, par_display_widow_penalties_code)) { 
4491            halfword v = unset ? null : display_widow_penalties_par; 
4492            if (par_display_widow_penalties(p)) {
4493                tex_flush_node(par_display_widow_penalties(p));
4494            }
4495            par_display_widow_penalties(p) = v ? tex_copy_node(v) : null;
4496        }
4497        if (tex_par_to_be_set(what, par_orphan_penalties_code)) { 
4498            halfword v = unset ? null : orphan_penalties_par; 
4499            if (par_orphan_penalties(p)) {
4500                tex_flush_node(par_orphan_penalties(p));
4501            }
4502            par_orphan_penalties(p) = v ? tex_copy_node(v) : null;
4503        }
4504        if (tex_par_to_be_set(what, par_baseline_skip_code)) { 
4505            halfword v = unset ? null : baseline_skip_par; 
4506            if (par_baseline_skip(p)) {
4507                tex_flush_node(par_baseline_skip(p));
4508            }
4509            par_baseline_skip(p) = v ? tex_copy_node(v) : null;
4510        }
4511        if (tex_par_to_be_set(what, par_line_skip_code)) { 
4512            halfword v = unset ? null : line_skip_par; 
4513            if (par_line_skip(p)) {
4514                tex_flush_node(par_line_skip(p));
4515            }
4516            par_line_skip(p) = v ? tex_copy_node(v) : null;
4517        }
4518        if (tex_par_to_be_set(what, par_line_skip_limit_code)) { 
4519            par_line_skip_limit(p) = unset ? null : line_skip_limit_par; 
4520        }
4521        if (tex_par_to_be_set(what, par_adjust_spacing_step_code)) { 
4522            par_adjust_spacing_step(p) = unset ? null : adjust_spacing_step_par; 
4523        }
4524        if (tex_par_to_be_set(what, par_adjust_spacing_shrink_code)) { 
4525            par_adjust_spacing_shrink(p) = unset ? null : adjust_spacing_shrink_par; 
4526        }
4527        if (tex_par_to_be_set(what, par_adjust_spacing_stretch_code)) { 
4528            par_adjust_spacing_stretch(p) = unset ? null : adjust_spacing_stretch_par; 
4529        }
4530        if (tex_par_to_be_set(what, par_hyphenation_mode_code)) { 
4531            par_hyphenation_mode(p) = unset ? null : hyphenation_mode_par; 
4532        }
4533        if (tex_par_to_be_set(what, par_shaping_penalties_mode_code)) { 
4534            par_shaping_penalties_mode(p) = unset ? null : shaping_penalties_mode_par; 
4535        }
4536        if (tex_par_to_be_set(what, par_shaping_penalty_code)) { 
4537            par_shaping_penalty(p) = unset ? null : shaping_penalty_par; 
4538        }
4539        if (tex_par_to_be_set(what, par_emergency_extra_stretch_code)) { 
4540            par_emergency_extra_stretch(p) = unset ? null : emergency_extra_stretch_par; 
4541        }
4542        if (tex_par_to_be_set(what, par_par_passes_code))  { 
4543            halfword v = unset ? null : par_passes_par; 
4544            if (par_par_passes(p)) {
4545                tex_flush_node(par_par_passes(p));
4546            }
4547            par_par_passes(p) = v ? tex_copy_node(v) : null;
4548        }
4549        if (tex_par_to_be_set(what, par_single_line_penalty_code)) { 
4550            par_single_line_penalty(p) = unset ? null : single_line_penalty_par; 
4551        }
4552     // tex_set_par_state(p, what);
4553        if (what == par_all_category) {
4554            par_state(p) = unset ? 0 : par_all_category;
4555        } else if (unset) {
4556            par_state(p) &= ~(what | par_state(p));
4557        } else {
4558            par_state(p) |= what;
4559        }
4560    }
4561}
4562
4563halfword tex_find_par_par(halfword head)
4564{
4565    if (head) {
4566        if (node_type(head) == temp_node) {
4567            head = node_next(head);
4568        }
4569        if (head && node_type(head) == par_node) {
4570            return head;
4571        }
4572    }
4573    return null;
4574}
4575
4576halfword tex_reversed_node_list(halfword list)
4577{
4578    if (list) {
4579        halfword prev = list;
4580        halfword last = list;
4581        halfword next = node_next(list);
4582        if (next) {
4583            while (1) {
4584                tex_couple_nodes(list, prev);
4585                if (node_type(list) == dir_node) {
4586                    node_subtype(list) = node_subtype(list) == cancel_dir_subtype ? normal_dir_subtype : cancel_dir_subtype;
4587                }
4588                if (next) {
4589                    prev = list;
4590                    list = next;
4591                    next = node_next(list);
4592                } else {
4593                    node_next(last) = null;
4594                    node_prev(list) = null;
4595                    return list;
4596                }
4597            }
4598        }
4599    }
4600    return list;
4601}
4602
4603/* */
4604
4605halfword tex_new_specification_node(halfword n, quarterword s, halfword options)
4606{
4607    halfword p = tex_new_node(specification_node, s);
4608    tex_new_specification_list(p, n, options);
4609    return p;
4610}
4611
4612void tex_dispose_specification_nodes(void) {
4613    if (par_shape_par)               { tex_flush_node(par_shape_par);               par_shape_par               = null; }
4614    if (par_passes_par)              { tex_flush_node(par_passes_par);              par_passes_par              = null; }
4615    if (inter_line_penalties_par)    { tex_flush_node(inter_line_penalties_par);    inter_line_penalties_par    = null; }
4616    if (club_penalties_par)          { tex_flush_node(club_penalties_par);          club_penalties_par          = null; }
4617    if (widow_penalties_par)         { tex_flush_node(widow_penalties_par);         widow_penalties_par         = null; }
4618    if (display_widow_penalties_par) { tex_flush_node(display_widow_penalties_par); display_widow_penalties_par = null; }
4619    if (math_forward_penalties_par)  { tex_flush_node(math_forward_penalties_par);  math_forward_penalties_par  = null; }
4620    if (math_backward_penalties_par) { tex_flush_node(math_backward_penalties_par); math_backward_penalties_par = null; }
4621    if (orphan_penalties_par)        { tex_flush_node(orphan_penalties_par);        orphan_penalties_par        = null; }
4622}
4623
4624void tex_null_specification_list(halfword a)
4625{
4626    specification_pointer(a) = NULL;
4627    specification_count(a) = 0;
4628}
4629
4630static void *tex_aux_allocate_specification(halfword p, int n, size_t *s)
4631{
4632    void *l = NULL;
4633    if (node_subtype(p) == par_passes_code) { 
4634        n *= par_passes_size;
4635    }
4636    *s = n * sizeof(memoryword);
4637    lmt_node_memory_state.extra_data.allocated += (int) *s;
4638    lmt_node_memory_state.extra_data.ptr = lmt_node_memory_state.extra_data.allocated;
4639    if (lmt_node_memory_state.extra_data.ptr > lmt_node_memory_state.extra_data.top) {
4640        lmt_node_memory_state.extra_data.top = lmt_node_memory_state.extra_data.ptr;
4641    }
4642    l = lmt_memory_calloc(n, sizeof(memoryword));
4643    if (! l) {
4644        tex_overflow_error("nodes", (int) *s);
4645    }
4646    return l;
4647}
4648
4649static void tex_aux_deallocate_specification(void *p, int n)
4650{
4651    size_t s = n * sizeof(memoryword);
4652    lmt_node_memory_state.extra_data.allocated -= (int) s; // not ok, we need to multiply by 3 for passes
4653    lmt_node_memory_state.extra_data.ptr = lmt_node_memory_state.extra_data.allocated;
4654    lmt_memory_free(p);
4655}
4656
4657void tex_new_specification_list(halfword a, halfword n, halfword o)
4658{
4659    size_t size = 0;
4660    specification_pointer(a) = tex_aux_allocate_specification(a, n, &size);
4661    specification_count(a) = specification_pointer(a) ? n : 0;
4662    specification_options(a) = o;
4663    if (node_subtype(a) == par_passes_code) { 
4664        for (int i = 1; i <= n; i++) { 
4665            tex_set_passes_threshold(a, i, max_dimension);
4666            tex_set_passes_badness(a, i, infinite_bad);        
4667            tex_set_passes_optional(a, i, 0x1000000);        
4668        }
4669    }
4670}
4671
4672void tex_dispose_specification_list(halfword a)
4673{
4674    if (specification_pointer(a)) {
4675        tex_aux_deallocate_specification(specification_pointer(a), specification_count(a));
4676        specification_pointer(a) = NULL;
4677        specification_count(a) = 0;
4678        specification_options(a) = 0;
4679    }
4680}
4681
4682void tex_copy_specification_list(halfword a, halfword b) {
4683    if (specification_pointer(b)) {
4684        size_t size = 0;
4685        specification_pointer(a) = tex_aux_allocate_specification(b, specification_count(b), &size);
4686        if (specification_pointer(a) && specification_pointer(b)) {
4687            specification_count(a) = specification_count(b);
4688            specification_options(a) = specification_options(b);
4689            memcpy(specification_pointer(a), specification_pointer(b), size);
4690        } else {
4691            specification_count(a) = 0;
4692            specification_options(a) = 0;
4693        }
4694    }
4695}
4696
4697void tex_shift_specification_list(halfword a, int n, int rotate)
4698{
4699    if (specification_pointer(a)) {
4700        halfword c = specification_count(a);
4701        if (rotate) {
4702            if (n > 0 && c > 0 && n < c && c != n) {
4703                size_t s = 0;
4704                memoryword *b = tex_aux_allocate_specification(a, c, &s);
4705                memoryword *p = specification_pointer(a);
4706                halfword m = c - n;
4707                s = m * sizeof(memoryword);
4708                memcpy(b, p + n, s);
4709                s = n * sizeof(memoryword);
4710                memcpy(b + m, p, s);
4711                tex_aux_deallocate_specification(specification_pointer(a), c);
4712                specification_pointer(a) = b;
4713            }
4714        } else {
4715            /* changed: zero check, else we wipe */
4716            if (n > 0) { 
4717                halfword o = 0;
4718                halfword m = 0;
4719                memoryword *b = NULL;
4720                if (n > 0 && c > 0 && n < c) {
4721                    size_t s = 0;
4722                    memoryword *p = specification_pointer(a);
4723                    o = specification_options(a);
4724                    m = c - n;
4725                    b = tex_aux_allocate_specification(a, m, &s);
4726                    memcpy(b, p + n, s);
4727                }
4728                if (c > 0) {
4729                    tex_aux_deallocate_specification(specification_pointer(a), c);
4730                }
4731                specification_pointer(a) = b;
4732                specification_count(a) = m;
4733                specification_options(a) = o;
4734            }
4735        }
4736    }
4737}
4738
4739/* */
4740
4741void tex_set_disc_field(halfword target, halfword location, halfword source)
4742{
4743    switch (location) {
4744        case pre_break_code:  target = disc_pre_break(target);  break;
4745        case post_break_code: target = disc_post_break(target); break;
4746        case no_break_code:   target = disc_no_break(target);   break;
4747    }
4748    node_prev(source) = null; /* don't expose this one! */
4749    if (source) {
4750        node_head(target) = source;
4751        node_tail(target) = tex_tail_of_node_list(source);
4752    } else {
4753        node_head(target) = null;
4754        node_tail(target) = null;
4755    }
4756}
4757
4758void tex_check_disc_field(halfword n)
4759{
4760    halfword p = disc_pre_break_head(n);
4761    disc_pre_break_tail(n) = p ? tex_tail_of_node_list(p) : null;
4762    p = disc_post_break_head(n);
4763    disc_post_break_tail(n) = p ? tex_tail_of_node_list(p) : null;
4764    p = disc_no_break_head(n);
4765    disc_no_break_tail(n) = p ? tex_tail_of_node_list(p) : null;
4766}
4767
4768void tex_set_discpart(halfword d, halfword h, halfword t, halfword code)
4769{
4770    halfword c = h;
4771    switch (node_subtype(d)) { 
4772        case automatic_discretionary_code:
4773        case mathematics_discretionary_code:
4774            code = glyph_discpart_always;
4775            break;
4776    }
4777    while (c) {
4778        if (node_type(c) == glyph_node) {
4779            set_glyph_discpart(c, code);
4780        }
4781        if (c == t) {
4782            break;
4783        } else {
4784            c = node_next(c);
4785        }
4786    }
4787}
4788
4789halfword tex_flatten_discretionaries(halfword head, int *count, int nest)
4790{
4791    halfword current = head;
4792    while (current) {
4793        halfword next = node_next(current);
4794        switch (node_type(current)) {
4795            case disc_node:
4796                {
4797                    halfword d = current;
4798                    halfword h = disc_no_break_head(d);
4799                    halfword t = disc_no_break_tail(d);
4800                    if (h) {
4801                        tex_set_discpart(current, h, t, glyph_discpart_replace);
4802                        tex_try_couple_nodes(t, next);
4803                        if (current == head) {
4804                            head = h;
4805                        } else {
4806                            tex_try_couple_nodes(node_prev(current), h);
4807                        }
4808                        disc_no_break_head(d) = null;
4809                    } else if (current == head) {
4810                        head = next;
4811                    } else {
4812                        tex_try_couple_nodes(node_prev(current), next);
4813                    }
4814                    tex_flush_node(d);
4815                    if (count) {
4816                        *count += 1;
4817                    }
4818                    break;
4819                }
4820            case hlist_node:
4821            case vlist_node:
4822                if (nest) {
4823                    halfword list = box_list(current);
4824                    if (list) {
4825                        box_list(current) = tex_flatten_discretionaries(list, count, nest);
4826                    }
4827                }
4828                break;
4829        }
4830        current = next;
4831    }
4832    return head;
4833}
4834
4835int tex_flatten_leaders(halfword box, int grp, int just_pack)
4836{
4837    halfword head = box ? box_list(box) : null;
4838    if (head) {
4839        halfword current = head;
4840        int count = 0;
4841        while (current) {
4842            halfword next = node_next(current);
4843            if (node_type(current) == glue_node && node_subtype(current) == u_leaders) {
4844                halfword prev = node_prev(current);
4845                halfword leader = glue_leader_ptr(current);
4846                if (leader && (node_type(leader) == hlist_node || node_type(leader) == vlist_node)) {
4847                    halfword packed = null;
4848                    halfword amount = glue_amount(current);
4849                    halfword callback = glue_callback(current);
4850                    double width = (double) amount;
4851                    switch (box_glue_sign(box)) {
4852                        case stretching_glue_sign:
4853                            if (glue_stretch_order(current) == box_glue_order(box)) {
4854                                width += glue_stretch(current) * (double) box_glue_set(box);
4855                            }
4856                            break;
4857                        case shrinking_glue_sign:
4858                            if (glue_shrink_order(current) == box_glue_order(box)) {
4859                                width -= glue_shrink(current) * (double) box_glue_set(box);
4860                            }
4861                            break;
4862                    }
4863                    if (node_type(leader) == hlist_node) {
4864                        packed = tex_hpack(box_list(leader), scaledround(width), packing_exactly, box_dir(leader), holding_none_option, box_limit_none);
4865                    } else {
4866                        packed = tex_vpack(box_list(leader), scaledround(width), packing_exactly, 0, box_dir(leader), holding_none_option, NULL);
4867                    }
4868                    box_list(leader) = box_list(packed);
4869                    box_width(leader) = box_width(packed);
4870                    box_height(leader) = box_height(packed);
4871                    box_depth(leader) = box_depth(packed);
4872                    box_glue_order(leader) = box_glue_order(packed);
4873                    box_glue_sign(leader) = box_glue_sign(packed);
4874                    box_glue_set(leader) = box_glue_set(packed);
4875                    set_box_package_state(leader, package_u_leader_set);
4876                    box_list(packed) = null;
4877                    tex_flush_node(packed);
4878                    glue_leader_ptr(current) = null;
4879                    tex_flush_node(current);
4880                    if (callback && ! just_pack) {
4881                        node_prev(leader) = null;
4882                        node_next(leader) = null;
4883                        leader = lmt_uleader_callback(leader, grp, callback);
4884                    }
4885                    tex_try_couple_nodes(leader, next);
4886                    if (current == head) {
4887                        box_list(box) = leader;
4888                    } else {
4889                        tex_try_couple_nodes(prev, leader);
4890                    }
4891                    count += 1;
4892                }
4893            }
4894            current = next;
4895        }
4896        return count;
4897    } else { 
4898        return 0;
4899    }
4900}
4901
4902/*tex
4903    This could of course be done in a \LUA\ loop but this is likely to be applied always so we
4904    provide a helper, also because we need to check the font. Adding this sort of violates the
4905    principle that we should this in \LUA\ instead but this time I permits myself to cheat.
4906*/
4907
4908void tex_soften_hyphens(halfword head, int *found, int *replaced)
4909{
4910    halfword current = head;
4911    while (current) {
4912        switch (node_type(current)) {
4913            case glyph_node:
4914                {
4915                    if (glyph_character(current) == 0x2D) {
4916                        /*
4917                            We actually need a callback for this? Or we can have a nested loop
4918                            helper in the nodelib.
4919                        */
4920                        ++(*found);
4921                        switch (glyph_discpart(current)) {
4922                            case glyph_discpart_unset:
4923                                /*tex Never seen by any disc handler. */
4924                                set_glyph_discpart(current, glyph_discpart_always);
4925                            case glyph_discpart_always:
4926                                /*tex A hard coded - in the input. */
4927                                break;
4928                            default :
4929                                if (tex_char_exists(glyph_font(current), 0xAD)) {
4930                                    ++(*replaced);
4931                                    glyph_character(current) = 0xAD;
4932                                }
4933                                break;
4934                        }
4935                    }
4936                    break;
4937                }
4938            case hlist_node:
4939            case vlist_node:
4940                {
4941                    halfword list = box_list(current);
4942                    if (list) {
4943                        tex_soften_hyphens(list, found, replaced);
4944                    }
4945                    break;
4946                }
4947        }
4948        current = node_next(current);
4949    }
4950}
4951
4952halfword tex_harden_spaces(halfword head, halfword tolerance, int* count)
4953{
4954    /* todo: take the context code */
4955    (void) tolerance;
4956    (void) count;
4957    return head;
4958}
4959
4960halfword tex_get_special_node_list(special_node_list_types list, halfword *tail)
4961{
4962    halfword h = null;
4963    halfword t = null;
4964    switch (list) {
4965        case page_insert_list_type:
4966            h = node_next(page_insert_head);
4967            if (h == page_insert_head) {
4968                h = null;
4969            }
4970            break;
4971        case contribute_list_type:
4972            h = node_next(contribute_head);
4973            break;
4974        case page_list_type:
4975            h = node_next(page_head);
4976            t = lmt_page_builder_state.page_tail;
4977            break;
4978        case temp_list_type:
4979            h = node_next(temp_head);
4980            break;
4981        case hold_list_type:
4982            h = node_next(hold_head);
4983            break;
4984        case post_adjust_list_type:
4985            h = node_next(post_adjust_head);
4986            t = lmt_packaging_state.post_adjust_tail;
4987            break;
4988        case pre_adjust_list_type:
4989            h = node_next(pre_adjust_head);
4990            t = lmt_packaging_state.pre_adjust_tail;
4991            break;
4992        case post_migrate_list_type:
4993            h = node_next(post_migrate_head);
4994            t = lmt_packaging_state.post_migrate_tail;
4995            break;
4996        case pre_migrate_list_type:
4997            h = node_next(pre_migrate_head);
4998            t = lmt_packaging_state.pre_migrate_tail;
4999            break;
5000        case align_list_type:
5001            h = node_next(align_head);
5002            break;
5003        case page_discards_list_type:
5004            h = lmt_packaging_state.page_discards_head;
5005            break;
5006        case split_discards_list_type:
5007            h = lmt_packaging_state.split_discards_head;
5008            break;
5009    }
5010    node_prev(h) = null;
5011    if (tail) {
5012        *tail = t ? t : (h ? tex_tail_of_node_list(h) : null);
5013    }
5014    return h;
5015};
5016
5017int tex_is_special_node_list(halfword n, int *istail)
5018{
5019    if (istail) {
5020        *istail = 0;
5021    }
5022    if (! n) {
5023        return -1;
5024    } else if (n == node_next(page_insert_head)) {
5025        return page_insert_list_type;
5026    } else if (n == node_next(contribute_head)) {
5027        return contribute_list_type;
5028    } else if (n == node_next(page_head) || n == lmt_page_builder_state.page_tail) {
5029        if (istail && n == lmt_page_builder_state.page_tail) {
5030            *istail = 0;
5031        }
5032        return page_list_type;
5033    } else if (n == node_next(temp_head)) {
5034        return temp_list_type;
5035    } else if (n == node_next(hold_head)) {
5036        return hold_list_type;
5037    } else if (n == node_next(post_adjust_head) || n == lmt_packaging_state.post_adjust_tail) {
5038        if (istail && n == lmt_packaging_state.post_adjust_tail) {
5039            *istail = 0;
5040        }
5041        return post_adjust_list_type;
5042    } else if (n == node_next(pre_adjust_head) || n == lmt_packaging_state.pre_adjust_tail) {
5043        if (istail && n == lmt_packaging_state.pre_adjust_tail) {
5044            *istail = 0;
5045        }
5046        return pre_adjust_list_type;
5047    } else if (n == node_next(post_migrate_head) || n == lmt_packaging_state.post_migrate_tail) {
5048        if (istail && n == lmt_packaging_state.post_migrate_tail) {
5049            *istail = 0;
5050        }
5051        return post_migrate_list_type;
5052    } else if (n == node_next(pre_migrate_head) || n == lmt_packaging_state.pre_migrate_tail) {
5053        if (istail && n == lmt_packaging_state.pre_migrate_tail) {
5054            *istail = 0;
5055        }
5056        return pre_migrate_list_type;
5057    } else if (n == node_next(align_head)) {
5058        return align_list_type;
5059    } else if (n == lmt_packaging_state.page_discards_head) {
5060        return page_discards_list_type;
5061    } else if (n == lmt_packaging_state.split_discards_head) {
5062        return split_discards_list_type;
5063 // } else if (n == lmt_page_builder_state.best_page_break) {
5064 //     return 10000;
5065    } else {
5066        return -1;
5067    }
5068};
5069
5070void tex_set_special_node_list(special_node_list_types list, halfword head)
5071{
5072    switch (list) {
5073        case page_insert_list_type:
5074            /*tex This is a circular list where page_insert_head stays. */
5075            if (head) {
5076                node_next(page_insert_head) = head;
5077                node_next(tex_tail_of_node_list(head)) = page_insert_head;
5078            } else {
5079                node_next(page_insert_head) = page_insert_head;
5080            }
5081            break;
5082        case contribute_list_type:
5083            node_next(contribute_head) = head;
5084            contribute_tail = head ? tex_tail_of_node_list(head) : contribute_head;
5085            break;
5086        case page_list_type:
5087            node_next(page_head) = head;
5088            lmt_page_builder_state.page_tail = head ? tex_tail_of_node_list(head) : page_head;
5089            break;
5090        case temp_list_type:
5091            node_next(temp_head) = head;
5092            break;
5093        case hold_list_type:
5094            node_next(hold_head) = head;
5095            break;
5096        case post_adjust_list_type:
5097            node_next(post_adjust_head) = head;
5098            lmt_packaging_state.post_adjust_tail = head ? tex_tail_of_node_list(head) : post_adjust_head;
5099            break;
5100        case pre_adjust_list_type:
5101            node_next(pre_adjust_head) = head;
5102            lmt_packaging_state.pre_adjust_tail = head ? tex_tail_of_node_list(head) : pre_adjust_head;
5103            break;
5104        case post_migrate_list_type:
5105            node_next(post_migrate_head) = head;
5106            lmt_packaging_state.post_migrate_tail = head ? tex_tail_of_node_list(head) : post_migrate_head;
5107            break;
5108        case pre_migrate_list_type:
5109            node_next(pre_migrate_head) = head;
5110            lmt_packaging_state.pre_migrate_tail = head ? tex_tail_of_node_list(head) : pre_migrate_head;
5111            break;
5112        case align_list_type:
5113            node_next(align_head) = head;
5114            break;
5115        case page_discards_list_type:
5116            lmt_packaging_state.page_discards_head = head;
5117            break;
5118        case split_discards_list_type:
5119            lmt_packaging_state.split_discards_head = head;
5120            break;
5121    }
5122};
5123
5124scaled tex_effective_glue(halfword parent, halfword glue)
5125{
5126    if (parent && glue) {
5127        switch (node_type(glue)) {
5128            case glue_node:
5129            case glue_spec_node:
5130                switch (node_type(parent)) {
5131                    case hlist_node:
5132                    case vlist_node:
5133                        {
5134                            double w = (double) glue_amount(glue);
5135                            switch (box_glue_sign(parent)) {
5136                                case stretching_glue_sign:
5137                                    if (glue_stretch_order(glue) == box_glue_order(parent)) {
5138                                        w += glue_stretch(glue) * (double) box_glue_set(parent);
5139                                    }
5140                                    break;
5141                                case shrinking_glue_sign:
5142                                    if (glue_shrink_order(glue) == box_glue_order(parent)) {
5143                                        w -= glue_shrink(glue) * (double) box_glue_set(parent);
5144                                    }
5145                                    break;
5146                            }
5147                            return (scaled) lmt_roundedfloat(w);
5148                        }
5149                    default:
5150                        return glue_amount(glue);
5151                }
5152                break;
5153        }
5154    }
5155    return 0;
5156}
5157