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