~ubuntu-branches/ubuntu/wily/luatex/wily

« back to all changes in this revision

Viewing changes to source/texk/web2c/luatexdir/tex/texnodes.w

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Preining
  • Date: 2010-04-29 00:47:19 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20100429004719-o42etkqe90n97b9e
Tags: 0.60.1-1
* new upstream release, adapt build-script patch
* disable patch: upstream-epstopdf_cc_no_xpdf_patching, included upstream
* disable patch: libpoppler-0.12, not needed anymore

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
% texnodes.w
 
2
 
 
3
% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org>
 
4
 
 
5
% This file is part of LuaTeX.
 
6
 
 
7
% LuaTeX is free software; you can redistribute it and/or modify it under
 
8
% the terms of the GNU General Public License as published by the Free
 
9
% Software Foundation; either version 2 of the License, or (at your
 
10
% option) any later version.
 
11
 
 
12
% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
 
13
% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
14
% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 
15
% License for more details.
 
16
 
 
17
% You should have received a copy of the GNU General Public License along
 
18
% with LuaTeX; if not, see <http://www.gnu.org/licenses/>. 
 
19
 
 
20
@ @c
 
21
static const char _svn_version[] =
 
22
    "$Id: texnodes.w 3612 2010-04-13 09:29:42Z taco $ "
 
23
    "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.1/source/texk/web2c/luatexdir/tex/texnodes.w $";
 
24
 
 
25
#include "ptexlib.h"
 
26
#include "lua/luatex-api.h"
 
27
 
 
28
@ @c
 
29
#undef name
 
30
 
 
31
#define noDEBUG
 
32
#define DEBUG_OUT stdout
 
33
 
 
34
#define adjust_pre subtype
 
35
#define attribute(A) eqtb[attribute_base+(A)].cint
 
36
 
 
37
#define uc_hyph int_par(uc_hyph_code)
 
38
#define cur_lang int_par(cur_lang_code)
 
39
#define left_hyphen_min int_par(left_hyphen_min_code)
 
40
#define right_hyphen_min int_par(right_hyphen_min_code)
 
41
 
 
42
#define text_direction int_par(text_direction_code)
 
43
 
 
44
#define MAX_CHAIN_SIZE 13
 
45
 
 
46
memory_word *volatile varmem = NULL;
 
47
 
 
48
#ifndef NDEBUG
 
49
char *varmem_sizes = NULL;
 
50
#endif
 
51
 
 
52
halfword var_mem_max = 0;
 
53
halfword rover = 0;
 
54
 
 
55
halfword free_chain[MAX_CHAIN_SIZE] = { null };
 
56
 
 
57
static int my_prealloc = 0;
 
58
 
 
59
int fix_node_lists = 1;
 
60
 
 
61
int free_error_seen = 0;
 
62
int copy_error_seen = 0;
 
63
 
 
64
halfword slow_get_node(int s);  /* defined below */
 
65
int copy_error(halfword p);     /* define below */
 
66
 
 
67
#define fake_node 100
 
68
#define fake_node_size 2
 
69
#define fake_node_name "fake"
 
70
 
 
71
#define variable_node_size 2
 
72
 
 
73
const char *node_fields_list[] =
 
74
    { "attr", "width", "depth", "height", "dir", "shift",
 
75
    "glue_order", "glue_sign", "glue_set", "list", NULL
 
76
};
 
77
const char *node_fields_rule[] =
 
78
    { "attr", "width", "depth", "height", "dir", NULL };
 
79
const char *node_fields_insert[] =
 
80
    { "attr", "cost", "depth", "height", "spec", "list", NULL };
 
81
const char *node_fields_mark[] = { "attr", "class", "mark", NULL };
 
82
const char *node_fields_adjust[] = { "attr", "list", NULL };
 
83
const char *node_fields_disc[] = { "attr", "pre", "post", "replace", NULL };
 
84
const char *node_fields_math[] = { "attr", "surround", NULL };
 
85
const char *node_fields_glue[] = { "attr", "spec", "leader", NULL };
 
86
const char *node_fields_kern[] = { "attr", "kern", "expansion_factor", NULL };
 
87
const char *node_fields_penalty[] = { "attr", "penalty", NULL };
 
88
 
 
89
const char *node_fields_unset[] =
 
90
    { "attr", "width", "depth", "height", "dir", "shrink",
 
91
    "glue_order", "glue_sign", "stretch", "span", "list", NULL
 
92
};
 
93
const char *node_fields_margin_kern[] = { "attr", "width", "glyph", NULL };
 
94
 
 
95
const char *node_fields_glyph[] =
 
96
    { "attr", "char", "font", "lang", "left", "right", "uchyph",
 
97
      "components", "xoffset", "yoffset", "width", "height", "depth", "expansion_factor", NULL
 
98
};
 
99
const char *node_fields_style[] = { "attr", "style", NULL };
 
100
const char *node_fields_choice[] =
 
101
    { "attr", "display", "text", "script", "scriptscript", NULL };
 
102
const char *node_fields_ord[] = { "attr", "nucleus", "sub", "sup", NULL };
 
103
const char *node_fields_op[] = { "attr", "nucleus", "sub", "sup", NULL };
 
104
const char *node_fields_bin[] = { "attr", "nucleus", "sub", "sup", NULL };
 
105
const char *node_fields_rel[] = { "attr", "nucleus", "sub", "sup", NULL };
 
106
const char *node_fields_open[] = { "attr", "nucleus", "sub", "sup", NULL };
 
107
const char *node_fields_close[] = { "attr", "nucleus", "sub", "sup", NULL };
 
108
const char *node_fields_punct[] = { "attr", "nucleus", "sub", "sup", NULL };
 
109
const char *node_fields_inner[] = { "attr", "nucleus", "sub", "sup", NULL };
 
110
const char *node_fields_under[] = { "attr", "nucleus", "sub", "sup", NULL };
 
111
const char *node_fields_over[] = { "attr", "nucleus", "sub", "sup", NULL };
 
112
const char *node_fields_vcenter[] = { "attr", "nucleus", "sub", "sup", NULL };
 
113
const char *node_fields_radical[] =
 
114
    { "attr", "nucleus", "sub", "sup", "left", "degree", NULL };
 
115
const char *node_fields_fraction[] =
 
116
    { "attr", "width", "num", "denom", "left", "right", NULL };
 
117
const char *node_fields_accent[] =
 
118
    { "attr", "nucleus", "sub", "sup", "accent", "bot_accent", NULL };
 
119
const char *node_fields_fence[] = { "attr", "delim", NULL };
 
120
const char *node_fields_math_char[] = { "attr", "fam", "char", NULL };
 
121
const char *node_fields_sub_box[] = { "attr", "list", NULL };
 
122
const char *node_fields_sub_mlist[] = { "attr", "list", NULL };
 
123
const char *node_fields_math_text_char[] = { "attr", "fam", "char", NULL };
 
124
const char *node_fields_delim[] =
 
125
    { "attr", "small_fam", "small_char", "large_fam", "large_char", NULL };
 
126
 
 
127
const char *node_fields_inserting[] =
 
128
    { "height", "last_ins_ptr", "best_ins_ptr", NULL };
 
129
 
 
130
const char *node_fields_splitup[] = { "height", "last_ins_ptr", "best_ins_ptr",
 
131
    "broken_ptr", "broken_ins", NULL
 
132
};
 
133
 
 
134
const char *node_fields_action[] = { "action_type", "named_id", "action_id",
 
135
    "file", "new_window", "data", "ref_count", NULL
 
136
};
 
137
const char *node_fields_attribute[] = { "number", "value", NULL };
 
138
 
 
139
const char *node_fields_glue_spec[] = { "width", "stretch", "shrink",
 
140
    "stretch_order", "shrink_order", "ref_count", "writable", NULL
 
141
};
 
142
const char *node_fields_attribute_list[] = { NULL };
 
143
 
 
144
const char *node_fields_whatsit_open[] =
 
145
    { "attr", "stream", "name", "area", "ext", NULL };
 
146
const char *node_fields_whatsit_write[] = { "attr", "stream", "data", NULL };
 
147
const char *node_fields_whatsit_close[] = { "attr", "stream", NULL };
 
148
const char *node_fields_whatsit_special[] = { "attr", "data", NULL };
 
149
 
 
150
const char *node_fields_whatsit_local_par[] =
 
151
    { "attr", "pen_inter", "pen_broken", "dir",
 
152
    "box_left", "box_left_width", "box_right", "box_right_width", NULL
 
153
};
 
154
const char *node_fields_whatsit_dir[] =
 
155
    { "attr", "dir", "level", "dvi_ptr", "dvi_h", NULL };
 
156
 
 
157
const char *node_fields_whatsit_pdf_literal[] =
 
158
    { "attr", "mode", "data", NULL };
 
159
const char *node_fields_whatsit_pdf_refobj[] = { "attr", "objnum", NULL };
 
160
const char *node_fields_whatsit_pdf_refxform[] =
 
161
    { "attr", "width", "depth", "height", "objnum", NULL };
 
162
const char *node_fields_whatsit_pdf_refximage[] =
 
163
    { "attr", "width", "depth", "height", "transform", "index", NULL };
 
164
const char *node_fields_whatsit_pdf_annot[] =
 
165
    { "attr", "width", "depth", "height", "objnum", "data", NULL };
 
166
const char *node_fields_whatsit_pdf_start_link[] =
 
167
    { "attr", "width", "depth", "height",
 
168
    "objnum", "link_attr", "action", NULL
 
169
};
 
170
const char *node_fields_whatsit_pdf_end_link[] = { "attr", NULL };
 
171
 
 
172
const char *node_fields_whatsit_pdf_dest[] =
 
173
    { "attr", "width", "depth", "height",
 
174
    "named_id", "dest_id", "dest_type", "xyz_zoom", "objnum", NULL
 
175
};
 
176
 
 
177
const char *node_fields_whatsit_pdf_thread[] =
 
178
    { "attr", "width", "depth", "height",
 
179
    "named_id", "thread_id", "thread_attr", NULL
 
180
};
 
181
 
 
182
const char *node_fields_whatsit_pdf_start_thread[] =
 
183
    { "attr", "width", "depth", "height",
 
184
    "named_id", "thread_id", "thread_attr", NULL
 
185
};
 
186
const char *node_fields_whatsit_pdf_end_thread[] = { "attr", NULL };
 
187
const char *node_fields_whatsit_pdf_save_pos[] = { "attr", NULL };
 
188
const char *node_fields_whatsit_late_lua[] =
 
189
    { "attr", "reg", "data", "name", NULL };
 
190
const char *node_fields_whatsit_close_lua[] = { "attr", "reg", NULL };
 
191
const char *node_fields_whatsit_pdf_colorstack[] =
 
192
    { "attr", "stack", "cmd", "data", NULL };
 
193
const char *node_fields_whatsit_pdf_setmatrix[] = { "attr", "data", NULL };
 
194
const char *node_fields_whatsit_pdf_save[] = { "attr", NULL };
 
195
const char *node_fields_whatsit_pdf_restore[] = { "attr", NULL };
 
196
const char *node_fields_whatsit_cancel_boundary[] = { "attr", NULL };
 
197
const char *node_fields_whatsit_user_defined[] =
 
198
    { "attr", "user_id", "type", "value", NULL };
 
199
 
 
200
node_info node_data[] = {
 
201
    {hlist_node, box_node_size, node_fields_list, "hlist"},
 
202
    {vlist_node, box_node_size, node_fields_list, "vlist"},
 
203
    {rule_node, rule_node_size, node_fields_rule, "rule"},
 
204
    {ins_node, ins_node_size, node_fields_insert, "ins"},
 
205
    {mark_node, mark_node_size, node_fields_mark, "mark"},
 
206
    {adjust_node, adjust_node_size, node_fields_adjust, "adjust"},
 
207
    {fake_node, fake_node_size, NULL, fake_node_name},  /* don't touch this! */
 
208
    {disc_node, disc_node_size, node_fields_disc, "disc"},
 
209
    {whatsit_node, -1, NULL, "whatsit"},
 
210
    {math_node, math_node_size, node_fields_math, "math"},
 
211
    {glue_node, glue_node_size, node_fields_glue, "glue"},
 
212
    {kern_node, kern_node_size, node_fields_kern, "kern"},
 
213
    {penalty_node, penalty_node_size, node_fields_penalty, "penalty"},
 
214
    {unset_node, box_node_size, node_fields_unset, "unset"},
 
215
    {style_node, style_node_size, node_fields_style, "style"},
 
216
    {choice_node, style_node_size, node_fields_choice, "choice"},
 
217
    {simple_noad, noad_size, node_fields_ord, "noad"},
 
218
    {old_op_noad, noad_size, node_fields_op, "op"},
 
219
    {old_bin_noad, noad_size, node_fields_bin, "bin"},
 
220
    {old_rel_noad, noad_size, node_fields_rel, "rel"},
 
221
    {old_open_noad, noad_size, node_fields_open, "open"},
 
222
    {old_close_noad, noad_size, node_fields_close, "close"},
 
223
    {old_punct_noad, noad_size, node_fields_punct, "punct"},
 
224
    {old_inner_noad, noad_size, node_fields_inner, "inner"},
 
225
    {radical_noad, radical_noad_size, node_fields_radical, "radical"},
 
226
    {fraction_noad, fraction_noad_size, node_fields_fraction, "fraction"},
 
227
    {old_under_noad, noad_size, node_fields_under, "under"},
 
228
    {old_over_noad, noad_size, node_fields_over, "over"},
 
229
    {accent_noad, accent_noad_size, node_fields_accent, "accent"},
 
230
    {old_vcenter_noad, noad_size, node_fields_vcenter, "vcenter"},
 
231
    {fence_noad, fence_noad_size, node_fields_fence, "fence"},
 
232
    {math_char_node, math_kernel_node_size, node_fields_math_char, "math_char"},
 
233
    {sub_box_node, math_kernel_node_size, node_fields_sub_box, "sub_box"},
 
234
    {sub_mlist_node, math_kernel_node_size, node_fields_sub_mlist, "sub_mlist"},
 
235
    {math_text_char_node, math_kernel_node_size, node_fields_math_text_char,
 
236
     "math_text_char"},
 
237
    {delim_node, math_shield_node_size, node_fields_delim, "delim"},
 
238
    {margin_kern_node, margin_kern_node_size, node_fields_margin_kern,
 
239
     "margin_kern"},
 
240
    {glyph_node, glyph_node_size, node_fields_glyph, "glyph"},
 
241
    {align_record_node, box_node_size, NULL, "align_record"},
 
242
    {pseudo_file_node, pseudo_file_node_size, NULL, "pseudo_file"},
 
243
    {pseudo_line_node, variable_node_size, NULL, "pseudo_line"},
 
244
    {inserting_node, page_ins_node_size, node_fields_inserting, "page_insert"},
 
245
    {split_up_node, page_ins_node_size, node_fields_splitup, "split_insert"},
 
246
    {expr_node, expr_node_size, NULL, "expr_stack"},
 
247
    {nesting_node, nesting_node_size, NULL, "nested_list"},
 
248
    {span_node, span_node_size, NULL, "span"},
 
249
    {attribute_node, attribute_node_size, node_fields_attribute, "attribute"},
 
250
    {glue_spec_node, glue_spec_size, node_fields_glue_spec, "glue_spec"},
 
251
    {attribute_list_node, attribute_node_size, node_fields_attribute_list,
 
252
     "attribute_list"},
 
253
    {action_node, pdf_action_size, node_fields_action, "action"},
 
254
    {temp_node, temp_node_size, NULL, "temp"},
 
255
    {align_stack_node, align_stack_node_size, NULL, "align_stack"},
 
256
    {movement_node, movement_node_size, NULL, "movement_stack"},
 
257
    {if_node, if_node_size, NULL, "if_stack"},
 
258
    {unhyphenated_node, active_node_size, NULL, "unhyphenated"},
 
259
    {hyphenated_node, active_node_size, NULL, "hyphenated"},
 
260
    {delta_node, delta_node_size, NULL, "delta"},
 
261
    {passive_node, passive_node_size, NULL, "passive"},
 
262
    {shape_node, variable_node_size, NULL, "shape"},
 
263
    {-1, -1, NULL, NULL}
 
264
};
 
265
 
 
266
#define last_normal_node shape_node
 
267
 
 
268
node_info whatsit_node_data[] = {
 
269
    {open_node, open_node_size, node_fields_whatsit_open, "open"},
 
270
    {write_node, write_node_size, node_fields_whatsit_write, "write"},
 
271
    {close_node, close_node_size, node_fields_whatsit_close, "close"},
 
272
    {special_node, special_node_size, node_fields_whatsit_special, "special"},
 
273
    {fake_node, fake_node_size, NULL, fake_node_name},
 
274
    {fake_node, fake_node_size, NULL, fake_node_name},
 
275
    {local_par_node, local_par_size, node_fields_whatsit_local_par,
 
276
     "local_par"},
 
277
    {dir_node, dir_node_size, node_fields_whatsit_dir, "dir"},
 
278
    {pdf_literal_node, write_node_size, node_fields_whatsit_pdf_literal,
 
279
     "pdf_literal"},
 
280
    {fake_node, fake_node_size, NULL, fake_node_name},
 
281
    {pdf_refobj_node, pdf_refobj_node_size, node_fields_whatsit_pdf_refobj,
 
282
     "pdf_refobj"},
 
283
    {fake_node, fake_node_size, NULL, fake_node_name},
 
284
    {pdf_refxform_node, pdf_refxform_node_size,
 
285
     node_fields_whatsit_pdf_refxform, "pdf_refxform"},
 
286
    {fake_node, fake_node_size, NULL, fake_node_name},
 
287
    {pdf_refximage_node, pdf_refximage_node_size,
 
288
     node_fields_whatsit_pdf_refximage, "pdf_refximage"},
 
289
    {pdf_annot_node, pdf_annot_node_size, node_fields_whatsit_pdf_annot,
 
290
     "pdf_annot"},
 
291
    {pdf_start_link_node, pdf_annot_node_size,
 
292
     node_fields_whatsit_pdf_start_link, "pdf_start_link"},
 
293
    {pdf_end_link_node, pdf_end_link_node_size,
 
294
     node_fields_whatsit_pdf_end_link, "pdf_end_link"},
 
295
    {fake_node, fake_node_size, NULL, fake_node_name},
 
296
    {pdf_dest_node, pdf_dest_node_size, node_fields_whatsit_pdf_dest,
 
297
     "pdf_dest"},
 
298
    {pdf_thread_node, pdf_thread_node_size, node_fields_whatsit_pdf_thread,
 
299
     "pdf_thread"},
 
300
    {pdf_start_thread_node, pdf_thread_node_size,
 
301
     node_fields_whatsit_pdf_start_thread, "pdf_start_thread"},
 
302
    {pdf_end_thread_node, pdf_end_thread_node_size,
 
303
     node_fields_whatsit_pdf_end_thread, "pdf_end_thread"},
 
304
    {pdf_save_pos_node, pdf_save_pos_node_size,
 
305
     node_fields_whatsit_pdf_save_pos, "pdf_save_pos"},
 
306
    {pdf_thread_data_node, pdf_thread_node_size, NULL, "pdf_thread_data"},
 
307
    {pdf_link_data_node, pdf_annot_node_size, NULL, "pdf_link_data"},
 
308
    {fake_node, fake_node_size, NULL, fake_node_name},
 
309
    {fake_node, fake_node_size, NULL, fake_node_name},
 
310
    {fake_node, fake_node_size, NULL, fake_node_name},
 
311
    {fake_node, fake_node_size, NULL, fake_node_name},
 
312
    {fake_node, fake_node_size, NULL, fake_node_name},
 
313
    {fake_node, fake_node_size, NULL, fake_node_name},
 
314
    {fake_node, fake_node_size, NULL, fake_node_name},
 
315
    {fake_node, fake_node_size, NULL, fake_node_name},
 
316
    {fake_node, fake_node_size, NULL, fake_node_name},
 
317
    {late_lua_node, late_lua_node_size, node_fields_whatsit_late_lua,
 
318
     "late_lua"},
 
319
    {close_lua_node, write_node_size, node_fields_whatsit_close_lua,
 
320
     "close_lua"},
 
321
    {fake_node, fake_node_size, NULL, fake_node_name},
 
322
    {fake_node, fake_node_size, NULL, fake_node_name},
 
323
    {pdf_colorstack_node, pdf_colorstack_node_size,
 
324
     node_fields_whatsit_pdf_colorstack, "pdf_colorstack"},
 
325
    {pdf_setmatrix_node, pdf_setmatrix_node_size,
 
326
     node_fields_whatsit_pdf_setmatrix, "pdf_setmatrix"},
 
327
    {pdf_save_node, pdf_save_node_size, node_fields_whatsit_pdf_save,
 
328
     "pdf_save"},
 
329
    {pdf_restore_node, pdf_restore_node_size, node_fields_whatsit_pdf_restore,
 
330
     "pdf_restore"},
 
331
    {cancel_boundary_node, cancel_boundary_size,
 
332
     node_fields_whatsit_cancel_boundary, "cancel_boundary"},
 
333
    {user_defined_node, user_defined_node_size,
 
334
     node_fields_whatsit_user_defined, "user_defined"},
 
335
    {-1, -1, NULL, NULL}
 
336
};
 
337
 
 
338
#define last_whatsit_node user_defined_node
 
339
 
 
340
@ @c
 
341
halfword new_node(int i, int j)
 
342
{
 
343
    int s;
 
344
    halfword n;
 
345
    s = get_node_size(i, j);
 
346
    n = get_node(s);
 
347
    /* it should be possible to do this memset at |free_node()| */
 
348
    /* type() and subtype() will be set below, and vlink() is
 
349
       set to null by |get_node()|, so we can do we clearing one
 
350
       word less than |s| */
 
351
    (void) memset((void *) (varmem + n + 1), 0,
 
352
                  (sizeof(memory_word) * ((unsigned) s - 1)));
 
353
    switch (i) {
 
354
    case glyph_node:
 
355
        init_lang_data(n);
 
356
        break;
 
357
    case hlist_node:
 
358
    case vlist_node:
 
359
        box_dir(n) = -1;
 
360
        break;
 
361
    case whatsit_node:
 
362
        if (j == open_node) {
 
363
            open_name(n) = get_nullstr();
 
364
            open_area(n) = open_name(n);
 
365
            open_ext(n) = open_name(n);
 
366
        }
 
367
        break;
 
368
    case disc_node:
 
369
        pre_break(n) = pre_break_head(n);
 
370
        type(pre_break(n)) = nesting_node;
 
371
        subtype(pre_break(n)) = pre_break_head(0);
 
372
        post_break(n) = post_break_head(n);
 
373
        type(post_break(n)) = nesting_node;
 
374
        subtype(post_break(n)) = post_break_head(0);
 
375
        no_break(n) = no_break_head(n);
 
376
        type(no_break(n)) = nesting_node;
 
377
        subtype(no_break(n)) = no_break_head(0);
 
378
        break;
 
379
    case rule_node:
 
380
        depth(n) = null_flag;
 
381
        height(n) = null_flag;
 
382
        rule_dir(n) = -1;
 
383
        /* fall through */
 
384
    case unset_node:
 
385
        width(n) = null_flag;
 
386
        break;
 
387
    case pseudo_line_node:
 
388
    case shape_node:
 
389
        /* this is a trick that makes |pseudo_files| slightly slower,
 
390
         but the overall allocation faster then an explicit test
 
391
         at the top of |new_node()|.
 
392
         */
 
393
        free_node(n, variable_node_size);
 
394
        n = slow_get_node(j);
 
395
        (void) memset((void *) (varmem + n + 1), 0,
 
396
                      (sizeof(memory_word) * ((unsigned) j - 1)));
 
397
        break;
 
398
    default:
 
399
        break;
 
400
    }
 
401
    /* handle synctex extension */
 
402
    switch (i) {
 
403
    case math_node:
 
404
        synctex_tag_math(n) = cur_input.synctex_tag_field;
 
405
        synctex_line_math(n) = line;
 
406
        break;
 
407
    case glue_node:
 
408
        synctex_tag_glue(n) = cur_input.synctex_tag_field;
 
409
        synctex_line_glue(n) = line;
 
410
        break;
 
411
    case kern_node:
 
412
        /* synctex ignores implicit kerns */
 
413
        if (j != 0) {
 
414
            synctex_tag_kern(n) = cur_input.synctex_tag_field;
 
415
            synctex_line_kern(n) = line;
 
416
        }
 
417
        break;
 
418
    case hlist_node:
 
419
    case vlist_node:
 
420
    case unset_node:
 
421
        synctex_tag_box(n) = cur_input.synctex_tag_field;
 
422
        synctex_line_box(n) = line;
 
423
        break;
 
424
    case rule_node:
 
425
        synctex_tag_rule(n) = cur_input.synctex_tag_field;
 
426
        synctex_line_rule(n) = line;
 
427
        break;
 
428
    }
 
429
    /* take care of attributes */
 
430
    if (nodetype_has_attributes(i)) {
 
431
        build_attribute_list(n);
 
432
    }
 
433
    type(n) = (quarterword) i;
 
434
    subtype(n) = (quarterword) j;
 
435
#ifdef DEBUG
 
436
    fprintf(DEBUG_OUT, "Alloc-ing %s node %d\n",
 
437
            get_node_name(type(n), subtype(n)), (int) n);
 
438
#endif
 
439
    return n;
 
440
}
 
441
 
 
442
halfword raw_glyph_node(void)
 
443
{
 
444
    register halfword n;
 
445
    n = get_node(glyph_node_size);
 
446
    (void) memset((void *) (varmem + n + 1), 0,
 
447
                  (sizeof(memory_word) * (glyph_node_size - 1)));
 
448
    type(n) = glyph_node;
 
449
    subtype(n) = 0;
 
450
    return n;
 
451
}
 
452
 
 
453
halfword new_glyph_node(void)
 
454
{
 
455
    register halfword n;
 
456
    n = get_node(glyph_node_size);
 
457
    (void) memset((void *) (varmem + n + 1), 0,
 
458
                  (sizeof(memory_word) * (glyph_node_size - 1)));
 
459
    type(n) = glyph_node;
 
460
    subtype(n) = 0;
 
461
    build_attribute_list(n);
 
462
    return n;
 
463
}
 
464
 
 
465
 
 
466
@ makes a duplicate of the node list that starts at |p| and returns a
 
467
   pointer to the new list 
 
468
@c
 
469
halfword do_copy_node_list(halfword p, halfword end)
 
470
{
 
471
    halfword q = null;          /* previous position in new list */
 
472
    halfword h = null;          /* head of the list */
 
473
    copy_error_seen = 0;
 
474
    while (p != end) {
 
475
        register halfword s = copy_node(p);
 
476
        if (h == null) {
 
477
            h = s;
 
478
        } else {
 
479
            couple_nodes(q, s);
 
480
        }
 
481
        q = s;
 
482
        p = vlink(p);
 
483
    }
 
484
    return h;
 
485
}
 
486
 
 
487
halfword copy_node_list(halfword p)
 
488
{
 
489
    return do_copy_node_list(p, null);
 
490
}
 
491
 
 
492
@ make a dupe of a single node 
 
493
@c
 
494
halfword copy_node(const halfword p)
 
495
{
 
496
    halfword r;                 /* current node being fabricated for new list */
 
497
    register halfword s;        /* a helper variable for copying into variable mem  */
 
498
    register int i;
 
499
    if (copy_error(p)) {
 
500
        r = new_node(temp_node, 0);
 
501
        return r;
 
502
    }
 
503
    i = get_node_size(type(p), subtype(p));
 
504
    r = get_node(i);
 
505
 
 
506
    (void) memcpy((void *) (varmem + r), (void *) (varmem + p),
 
507
                  (sizeof(memory_word) * (unsigned) i));
 
508
 
 
509
    /* handle synctex extension */
 
510
    switch (type(p)) {
 
511
    case math_node:
 
512
        synctex_tag_math(r) = cur_input.synctex_tag_field;
 
513
        synctex_line_math(r) = line;
 
514
        break;
 
515
    case kern_node:
 
516
        synctex_tag_kern(r) = cur_input.synctex_tag_field;
 
517
        synctex_line_kern(r) = line;
 
518
        break;
 
519
    }
 
520
 
 
521
    if (nodetype_has_attributes(type(p))) {
 
522
        add_node_attr_ref(node_attr(p));
 
523
        alink(r) = null;        /* needs checking */
 
524
    }
 
525
    vlink(r) = null;
 
526
 
 
527
 
 
528
    switch (type(p)) {
 
529
    case glyph_node:
 
530
        s = copy_node_list(lig_ptr(p));
 
531
        lig_ptr(r) = s;
 
532
        break;
 
533
    case glue_node:
 
534
        add_glue_ref(glue_ptr(p));
 
535
        s = copy_node_list(leader_ptr(p));
 
536
        leader_ptr(r) = s;
 
537
        break;
 
538
    case hlist_node:
 
539
    case vlist_node:
 
540
    case unset_node:
 
541
        s = copy_node_list(list_ptr(p));
 
542
        list_ptr(r) = s;
 
543
        break;
 
544
    case ins_node:
 
545
        add_glue_ref(split_top_ptr(p));
 
546
        s = copy_node_list(ins_ptr(p));
 
547
        ins_ptr(r) = s;
 
548
        break;
 
549
    case margin_kern_node:
 
550
        s = copy_node(margin_char(p));
 
551
        margin_char(r) = s;
 
552
        break;
 
553
    case disc_node:
 
554
        pre_break(r) = pre_break_head(r);
 
555
        if (vlink_pre_break(p) != null) {
 
556
            s = copy_node_list(vlink_pre_break(p));
 
557
            alink(s) = pre_break(r);
 
558
            tlink_pre_break(r) = tail_of_list(s);
 
559
            vlink_pre_break(r) = s;
 
560
        } else {
 
561
            assert(tlink(pre_break(r)) == null);
 
562
        }
 
563
        post_break(r) = post_break_head(r);
 
564
        if (vlink_post_break(p) != null) {
 
565
            s = copy_node_list(vlink_post_break(p));
 
566
            alink(s) = post_break(r);
 
567
            tlink_post_break(r) = tail_of_list(s);
 
568
            vlink_post_break(r) = s;
 
569
        } else {
 
570
            assert(tlink_post_break(r) == null);
 
571
        }
 
572
        no_break(r) = no_break_head(r);
 
573
        if (vlink(no_break(p)) != null) {
 
574
            s = copy_node_list(vlink_no_break(p));
 
575
            alink(s) = no_break(r);
 
576
            tlink_no_break(r) = tail_of_list(s);
 
577
            vlink_no_break(r) = s;
 
578
        } else {
 
579
            assert(tlink_no_break(r) == null);
 
580
        }
 
581
        break;
 
582
    case mark_node:
 
583
        add_token_ref(mark_ptr(p));
 
584
        break;
 
585
    case adjust_node:
 
586
        s = copy_node_list(adjust_ptr(p));
 
587
        adjust_ptr(r) = s;
 
588
        break;
 
589
 
 
590
    case choice_node:
 
591
        s = copy_node_list(display_mlist(p));
 
592
        display_mlist(r) = s;
 
593
        s = copy_node_list(text_mlist(p));
 
594
        text_mlist(r) = s;
 
595
        s = copy_node_list(script_mlist(p));
 
596
        script_mlist(r) = s;
 
597
        s = copy_node_list(script_script_mlist(p));
 
598
        script_script_mlist(r) = s;
 
599
        break;
 
600
    case simple_noad:
 
601
    case radical_noad:
 
602
    case accent_noad:
 
603
        s = copy_node_list(nucleus(p));
 
604
        nucleus(r) = s;
 
605
        s = copy_node_list(subscr(p));
 
606
        subscr(r) = s;
 
607
        s = copy_node_list(supscr(p));
 
608
        supscr(r) = s;
 
609
        if (type(p) == accent_noad) {
 
610
            s = copy_node_list(accent_chr(p));
 
611
            accent_chr(r) = s;
 
612
            s = copy_node_list(bot_accent_chr(p));
 
613
            bot_accent_chr(r) = s;
 
614
        } else if (type(p) == radical_noad) {
 
615
            s = copy_node(left_delimiter(p));
 
616
            left_delimiter(r) = s;
 
617
            s = copy_node_list(degree(p));
 
618
            degree(r) = s;
 
619
        }
 
620
        break;
 
621
    case fence_noad:
 
622
        s = copy_node(delimiter(p));
 
623
        delimiter(r) = s;
 
624
        break;
 
625
    case sub_box_node:
 
626
    case sub_mlist_node:
 
627
        s = copy_node_list(math_list(p));
 
628
        math_list(r) = s;
 
629
        break;
 
630
    case fraction_noad:
 
631
        s = copy_node_list(numerator(p));
 
632
        numerator(r) = s;
 
633
        s = copy_node_list(denominator(p));
 
634
        denominator(r) = s;
 
635
        s = copy_node(left_delimiter(p));
 
636
        left_delimiter(r) = s;
 
637
        s = copy_node(right_delimiter(p));
 
638
        right_delimiter(r) = s;
 
639
        break;
 
640
    case glue_spec_node:
 
641
        glue_ref_count(r) = null;
 
642
        break;
 
643
    case whatsit_node:
 
644
        switch (subtype(p)) {
 
645
        case dir_node:
 
646
        case local_par_node:
 
647
            break;
 
648
        case write_node:
 
649
        case special_node:
 
650
            add_token_ref(write_tokens(p));
 
651
            break;
 
652
        case pdf_literal_node:
 
653
            copy_pdf_literal(r, p);
 
654
            break;
 
655
        case pdf_colorstack_node:
 
656
            if (pdf_colorstack_cmd(p) <= colorstack_data)
 
657
                add_token_ref(pdf_colorstack_data(p));
 
658
            break;
 
659
        case pdf_setmatrix_node:
 
660
            add_token_ref(pdf_setmatrix_data(p));
 
661
            break;
 
662
        case late_lua_node:
 
663
            if (late_lua_name(p) > 0)
 
664
                add_token_ref(late_lua_name(p));
 
665
            add_token_ref(late_lua_data(p));
 
666
            break;
 
667
        case pdf_annot_node:
 
668
            add_token_ref(pdf_annot_data(p));
 
669
            break;
 
670
        case pdf_start_link_node:
 
671
            if (pdf_link_attr(r) != null)
 
672
                add_token_ref(pdf_link_attr(r));
 
673
            add_action_ref(pdf_link_action(r));
 
674
            break;
 
675
        case pdf_dest_node:
 
676
            if (pdf_dest_named_id(p) > 0)
 
677
                add_token_ref(pdf_dest_id(p));
 
678
            break;
 
679
        case pdf_thread_node:
 
680
        case pdf_start_thread_node:
 
681
            if (pdf_thread_named_id(p) > 0)
 
682
                add_token_ref(pdf_thread_id(p));
 
683
            if (pdf_thread_attr(p) != null)
 
684
                add_token_ref(pdf_thread_attr(p));
 
685
            break;
 
686
        case user_defined_node:
 
687
            switch (user_node_type(p)) {
 
688
            case 'a':
 
689
                add_node_attr_ref(user_node_value(p));
 
690
                break;
 
691
            case 't':
 
692
                add_token_ref(user_node_value(p));
 
693
                break;
 
694
            case 's':
 
695
                /* |add_string_ref(user_node_value(p));| *//* if this was mpost .. */
 
696
                break;
 
697
            case 'n':
 
698
                s = copy_node_list(user_node_value(p));
 
699
                user_node_value(r) = s;
 
700
                break;
 
701
            }
 
702
            break;
 
703
#if 0
 
704
        case style_node:
 
705
        case delim_node:
 
706
        case math_char_node:
 
707
        case math_text_char_node:
 
708
        break;
 
709
#else
 
710
        default:
 
711
#endif
 
712
            break;
 
713
        }
 
714
        break;
 
715
    }
 
716
#ifdef DEBUG
 
717
    fprintf(DEBUG_OUT, "Alloc-ing %s node %d (copy of %d)\n",
 
718
            get_node_name(type(r), subtype(r)), (int) r, (int) p);
 
719
#endif
 
720
    return r;
 
721
}
 
722
 
 
723
@ @c
 
724
int valid_node(halfword p)
 
725
{
 
726
    if (p > my_prealloc) {
 
727
        if (p < var_mem_max) {
 
728
#ifndef NDEBUG
 
729
            if (varmem_sizes[p] > 0)
 
730
#endif
 
731
                return 1;
 
732
        }
 
733
    } else {
 
734
        return 0;
 
735
    }
 
736
    return 0;
 
737
}
 
738
 
 
739
@ @c
 
740
static void do_free_error(halfword p)
 
741
{
 
742
    halfword r;
 
743
    char errstr[255] = { 0 };
 
744
    const char *errhlp[] = {
 
745
        "When I tried to free the node mentioned in the error message, it turned",
 
746
        "out it was not (or no longer) actually in use.",
 
747
        "Errors such as these are often caused by Lua node list alteration,",
 
748
        "but could also point to a bug in the executable. It should be safe to continue.",
 
749
        NULL
 
750
    };
 
751
 
 
752
    check_node_mem();
 
753
    if (free_error_seen)
 
754
        return;
 
755
 
 
756
    r = null;
 
757
    free_error_seen = 1;
 
758
    if (type(p) == glyph_node) {
 
759
        snprintf(errstr, 255,
 
760
                 "Attempt to double-free glyph (%c) node %d, ignored",
 
761
                 (int) character(p), (int) p);
 
762
    } else {
 
763
        snprintf(errstr, 255, "Attempt to double-free %s node %d, ignored",
 
764
                 get_node_name(type(p), subtype(p)), (int) p);
 
765
    }
 
766
    tex_error(errstr, errhlp);
 
767
#ifndef NDEBUG
 
768
    for (r = my_prealloc + 1; r < var_mem_max; r++) {
 
769
        if (vlink(r) == p) {
 
770
            halfword s = r;
 
771
            while (s > my_prealloc && varmem_sizes[s] == 0)
 
772
                s--;
 
773
            if (s != null
 
774
                && s != my_prealloc
 
775
                && s != var_mem_max
 
776
                && (r - s) < get_node_size(type(s), subtype(s))
 
777
                && alink(s) != p) {
 
778
 
 
779
                if (type(s) == disc_node) {
 
780
                    fprintf(stdout,
 
781
                            "  pointed to from %s node %d (vlink %d, alink %d): ",
 
782
                            get_node_name(type(s), subtype(s)), (int) s,
 
783
                            (int) vlink(s), (int) alink(s));
 
784
                    fprintf(stdout, "pre_break(%d,%d,%d), ",
 
785
                            (int) vlink_pre_break(s), (int) tlink(pre_break(s)),
 
786
                            (int) alink(pre_break(s)));
 
787
                    fprintf(stdout, "post_break(%d,%d,%d), ",
 
788
                            (int) vlink_post_break(s),
 
789
                            (int) tlink(post_break(s)),
 
790
                            (int) alink(post_break(s)));
 
791
                    fprintf(stdout, "no_break(%d,%d,%d)",
 
792
                            (int) vlink_no_break(s), (int) tlink(no_break(s)),
 
793
                            (int) alink(no_break(s)));
 
794
                    fprintf(stdout, "\n");
 
795
                } else {
 
796
                    if (vlink(s) == p
 
797
                        || (type(s) == glyph_node && lig_ptr(s) == p)
 
798
                        || (type(s) == vlist_node && list_ptr(s) == p)
 
799
                        || (type(s) == hlist_node && list_ptr(s) == p)
 
800
                        || (type(s) == unset_node && list_ptr(s) == p)
 
801
                        || (type(s) == ins_node && ins_ptr(s) == p)
 
802
                        ) {
 
803
                        fprintf(stdout,
 
804
                                "  pointed to from %s node %d (vlink %d, alink %d): ",
 
805
                                get_node_name(type(s), subtype(s)), (int) s,
 
806
                                (int) vlink(s), (int) alink(s));
 
807
                        if (type(s) == glyph_node) {
 
808
                            fprintf(stdout, "lig_ptr(%d)", (int) lig_ptr(s));
 
809
                        } else if (type(s) == vlist_node
 
810
                                   || type(s) == hlist_node) {
 
811
                            fprintf(stdout, "list_ptr(%d)", (int) list_ptr(s));
 
812
                        }
 
813
                        fprintf(stdout, "\n");
 
814
                    } else {
 
815
                        if ((type(s) != penalty_node)
 
816
                            && (type(s) != math_node)
 
817
                            && (type(s) != kern_node)
 
818
                            ) {
 
819
                            fprintf(stdout, "  pointed to from %s node %d\n",
 
820
                                    get_node_name(type(s), subtype(s)),
 
821
                                    (int) s);
 
822
                        }
 
823
                    }
 
824
                }
 
825
            }
 
826
        }
 
827
    }
 
828
#endif
 
829
}
 
830
 
 
831
static int free_error(halfword p)
 
832
{
 
833
    assert(p > my_prealloc);
 
834
    assert(p < var_mem_max);
 
835
#ifndef NDEBUG
 
836
    if (varmem_sizes[p] == 0) {
 
837
        do_free_error(p);
 
838
        return 1;               /* double free */
 
839
    }
 
840
#endif
 
841
    return 0;
 
842
}
 
843
 
 
844
 
 
845
@ @c
 
846
static void do_copy_error(halfword p)
 
847
{
 
848
    char errstr[255] = { 0 };
 
849
    const char *errhlp[] = {
 
850
        "When I tried to copy the node mentioned in the error message, it turned",
 
851
        "out it was not (or no longer) actually in use.",
 
852
        "Errors such as these are often caused by Lua node list alteration,",
 
853
        "but could also point to a bug in the executable. It should be safe to continue.",
 
854
        NULL
 
855
    };
 
856
 
 
857
    if (copy_error_seen)
 
858
        return;
 
859
 
 
860
    copy_error_seen = 1;
 
861
    if (type(p) == glyph_node) {
 
862
        snprintf(errstr, 255,
 
863
                 "Attempt to copy free glyph (%c) node %d, ignored",
 
864
                 (int) character(p), (int) p);
 
865
    } else {
 
866
        snprintf(errstr, 255, "Attempt to copy free %s node %d, ignored",
 
867
                 get_node_name(type(p), subtype(p)), (int) p);
 
868
    }
 
869
    tex_error(errstr, errhlp);
 
870
}
 
871
 
 
872
 
 
873
int copy_error(halfword p)
 
874
{
 
875
    assert(p >= 0);
 
876
    assert(p < var_mem_max);
 
877
#ifndef NDEBUG
 
878
    if (p > my_prealloc && varmem_sizes[p] == 0) {
 
879
        do_copy_error(p);
 
880
        return 1;               /* copy free node */
 
881
    }
 
882
#endif
 
883
    return 0;
 
884
}
 
885
 
 
886
 
 
887
@ @c
 
888
void flush_node(halfword p)
 
889
{
 
890
 
 
891
    if (p == null)              /* legal, but no-op */
 
892
        return;
 
893
 
 
894
#ifdef DEBUG
 
895
    fprintf(DEBUG_OUT, "Free-ing %s node %d\n",
 
896
            get_node_name(type(p), subtype(p)), (int) p);
 
897
#endif
 
898
    if (free_error(p))
 
899
        return;
 
900
 
 
901
    switch (type(p)) {
 
902
    case glyph_node:
 
903
        flush_node_list(lig_ptr(p));
 
904
        break;
 
905
    case glue_node:
 
906
        delete_glue_ref(glue_ptr(p));
 
907
        flush_node_list(leader_ptr(p));
 
908
        break;
 
909
 
 
910
    case attribute_node:
 
911
    case attribute_list_node:
 
912
    case temp_node:
 
913
    case glue_spec_node:
 
914
    case rule_node:
 
915
    case kern_node:
 
916
    case math_node:
 
917
    case penalty_node:
 
918
        break;
 
919
 
 
920
    case hlist_node:
 
921
    case vlist_node:
 
922
    case unset_node:
 
923
        flush_node_list(list_ptr(p));
 
924
        break;
 
925
    case whatsit_node:
 
926
        switch (subtype(p)) {
 
927
 
 
928
        case dir_node:
 
929
            break;
 
930
        case open_node:
 
931
        case write_node:
 
932
        case close_node:
 
933
        case pdf_save_node:
 
934
        case pdf_restore_node:
 
935
        case cancel_boundary_node:
 
936
        case close_lua_node:
 
937
        case pdf_refobj_node:
 
938
        case pdf_refxform_node:
 
939
        case pdf_refximage_node:
 
940
        case pdf_end_link_node:
 
941
        case pdf_end_thread_node:
 
942
        case pdf_save_pos_node:
 
943
        case local_par_node:
 
944
            break;
 
945
 
 
946
        case special_node:
 
947
            delete_token_ref(write_tokens(p));
 
948
            break;
 
949
        case pdf_literal_node:
 
950
            free_pdf_literal(p);
 
951
            break;
 
952
        case pdf_colorstack_node:
 
953
            if (pdf_colorstack_cmd(p) <= colorstack_data)
 
954
                delete_token_ref(pdf_colorstack_data(p));
 
955
            break;
 
956
        case pdf_setmatrix_node:
 
957
            delete_token_ref(pdf_setmatrix_data(p));
 
958
            break;
 
959
        case late_lua_node:
 
960
            if (late_lua_name(p) > 0)
 
961
                delete_token_ref(late_lua_name(p));
 
962
            delete_token_ref(late_lua_data(p));
 
963
            break;
 
964
        case pdf_annot_node:
 
965
            delete_token_ref(pdf_annot_data(p));
 
966
            break;
 
967
 
 
968
        case pdf_link_data_node:
 
969
            break;
 
970
 
 
971
        case pdf_start_link_node:
 
972
            if (pdf_link_attr(p) != null)
 
973
                delete_token_ref(pdf_link_attr(p));
 
974
            delete_action_ref(pdf_link_action(p));
 
975
            break;
 
976
        case pdf_dest_node:
 
977
            if (pdf_dest_named_id(p) > 0)
 
978
                delete_token_ref(pdf_dest_id(p));
 
979
            break;
 
980
 
 
981
        case pdf_thread_data_node:
 
982
            break;
 
983
 
 
984
        case pdf_thread_node:
 
985
        case pdf_start_thread_node:
 
986
            if (pdf_thread_named_id(p) > 0)
 
987
                delete_token_ref(pdf_thread_id(p));
 
988
            if (pdf_thread_attr(p) != null)
 
989
                delete_token_ref(pdf_thread_attr(p));
 
990
            break;
 
991
        case user_defined_node:
 
992
            switch (user_node_type(p)) {
 
993
            case 'a':
 
994
                delete_attribute_ref(user_node_value(p));
 
995
                break;
 
996
            case 't':
 
997
                delete_token_ref(user_node_value(p));
 
998
                break;
 
999
            case 'n':
 
1000
                flush_node_list(user_node_value(p));
 
1001
                break;
 
1002
            case 's':
 
1003
                /* |delete_string_ref(user_node_value(p));| *//* if this was mpost .. */
 
1004
                break;
 
1005
            case 'd':
 
1006
                break;
 
1007
            default:
 
1008
                {
 
1009
                    const char *hlp[] = {
 
1010
                        "The type of the value in a user defined whatsit node should be one",
 
1011
                        "of 'a' (attribute list), 'd' (number), 'n' (node list), 's' (string),",
 
1012
                        "or 't' (tokenlist). Yours has an unknown type, and therefore I don't",
 
1013
                        "know how to free the node's value. A memory leak may result.",
 
1014
                        NULL
 
1015
                    };
 
1016
                    tex_error("Unidentified user defined whatsit", hlp);
 
1017
                }
 
1018
                break;
 
1019
            }
 
1020
            break;
 
1021
 
 
1022
        default:
 
1023
            confusion("ext3");
 
1024
            return;
 
1025
 
 
1026
        }
 
1027
        break;
 
1028
    case ins_node:
 
1029
        flush_node_list(ins_ptr(p));
 
1030
        delete_glue_ref(split_top_ptr(p));
 
1031
        break;
 
1032
    case margin_kern_node:
 
1033
        flush_node(margin_char(p));
 
1034
        break;
 
1035
    case mark_node:
 
1036
        delete_token_ref(mark_ptr(p));
 
1037
        break;
 
1038
    case disc_node:
 
1039
        flush_node_list(vlink(pre_break(p)));
 
1040
        flush_node_list(vlink(post_break(p)));
 
1041
        flush_node_list(vlink(no_break(p)));
 
1042
        break;
 
1043
    case adjust_node:
 
1044
        flush_node_list(adjust_ptr(p));
 
1045
        break;
 
1046
    case style_node:           /* nothing to do */
 
1047
        break;
 
1048
    case choice_node:
 
1049
        flush_node_list(display_mlist(p));
 
1050
        flush_node_list(text_mlist(p));
 
1051
        flush_node_list(script_mlist(p));
 
1052
        flush_node_list(script_script_mlist(p));
 
1053
        break;
 
1054
    case simple_noad:
 
1055
    case radical_noad:
 
1056
    case accent_noad:
 
1057
        flush_node_list(nucleus(p));
 
1058
        flush_node_list(subscr(p));
 
1059
        flush_node_list(supscr(p));
 
1060
        if (type(p) == accent_noad) {
 
1061
            flush_node_list(accent_chr(p));
 
1062
            flush_node_list(bot_accent_chr(p));
 
1063
        } else if (type(p) == radical_noad) {
 
1064
            flush_node(left_delimiter(p));
 
1065
            flush_node_list(degree(p));
 
1066
        }
 
1067
        break;
 
1068
    case fence_noad:
 
1069
        flush_node(delimiter(p));
 
1070
        break;
 
1071
    case delim_node:           /* nothing to do */
 
1072
    case math_char_node:
 
1073
    case math_text_char_node:
 
1074
        break;
 
1075
    case sub_box_node:
 
1076
    case sub_mlist_node:
 
1077
        flush_node_list(math_list(p));
 
1078
        break;
 
1079
    case fraction_noad:
 
1080
        flush_node_list(numerator(p));
 
1081
        flush_node_list(denominator(p));
 
1082
        flush_node(left_delimiter(p));
 
1083
        flush_node(right_delimiter(p));
 
1084
        break;
 
1085
    case pseudo_file_node:
 
1086
        flush_node_list(pseudo_lines(p));
 
1087
        break;
 
1088
    case pseudo_line_node:
 
1089
    case shape_node:
 
1090
        free_node(p, subtype(p));
 
1091
        return;
 
1092
        break;
 
1093
    case align_stack_node:
 
1094
    case span_node:
 
1095
    case movement_node:
 
1096
    case if_node:
 
1097
    case nesting_node:
 
1098
    case unhyphenated_node:
 
1099
    case hyphenated_node:
 
1100
    case delta_node:
 
1101
    case passive_node:
 
1102
    case action_node:
 
1103
    case inserting_node:
 
1104
    case split_up_node:
 
1105
    case expr_node:
 
1106
        break;
 
1107
    default:
 
1108
        fprintf(stdout, "flush_node: type is %d\n", type(p));
 
1109
        return;
 
1110
 
 
1111
    }
 
1112
    if (nodetype_has_attributes(type(p)))
 
1113
        delete_attribute_ref(node_attr(p));
 
1114
    free_node(p, get_node_size(type(p), subtype(p)));
 
1115
    return;
 
1116
}
 
1117
 
 
1118
@ @c
 
1119
void flush_node_list(halfword pp)
 
1120
{                               /* erase list of nodes starting at |p| */
 
1121
    register halfword p = pp;
 
1122
    free_error_seen = 0;
 
1123
    if (p == null)              /* legal, but no-op */
 
1124
        return;
 
1125
    if (free_error(p))
 
1126
        return;
 
1127
 
 
1128
    while (p != null) {
 
1129
        register halfword q = vlink(p);
 
1130
        flush_node(p);
 
1131
        p = q;
 
1132
    }
 
1133
}
 
1134
 
 
1135
@ @c
 
1136
static int test_count = 1;
 
1137
 
 
1138
#define dorangetest(a,b,c)  do {                                        \
 
1139
    if (!(b>=0 && b<c)) {                                               \
 
1140
      fprintf(stdout,"For node p:=%d, 0<=%d<%d (l.%d,r.%d)\n",          \
 
1141
              (int)a, (int)b, (int)c, __LINE__,test_count);             \
 
1142
      confusion("dorangetest");                                        \
 
1143
    } } while (0)
 
1144
 
 
1145
#define dotest(a,b,c) do {                                              \
 
1146
    if (b!=c) {                                                         \
 
1147
      fprintf(stdout,"For node p:=%d, %d==%d (l.%d,r.%d)\n",            \
 
1148
              (int)a, (int)b, (int)c, __LINE__,test_count);             \
 
1149
      confusion("dotest");                                             \
 
1150
    } } while (0)
 
1151
 
 
1152
#define check_action_ref(a)     { dorangetest(p,a,var_mem_max); }
 
1153
#define check_glue_ref(a)       { dorangetest(p,a,var_mem_max); }
 
1154
#define check_attribute_ref(a)  { dorangetest(p,a,var_mem_max); }
 
1155
#define check_token_ref(a)      assert(1)
 
1156
 
 
1157
void check_node(halfword p)
 
1158
{
 
1159
 
 
1160
    switch (type(p)) {
 
1161
    case glyph_node:
 
1162
        dorangetest(p, lig_ptr(p), var_mem_max);
 
1163
        break;
 
1164
    case glue_node:
 
1165
        check_glue_ref(glue_ptr(p));
 
1166
        dorangetest(p, leader_ptr(p), var_mem_max);
 
1167
        break;
 
1168
    case hlist_node:
 
1169
    case vlist_node:
 
1170
    case unset_node:
 
1171
    case align_record_node:
 
1172
        dorangetest(p, list_ptr(p), var_mem_max);
 
1173
        break;
 
1174
    case ins_node:
 
1175
        dorangetest(p, ins_ptr(p), var_mem_max);
 
1176
        check_glue_ref(split_top_ptr(p));
 
1177
        break;
 
1178
    case whatsit_node:
 
1179
        switch (subtype(p)) {
 
1180
        case special_node:
 
1181
            check_token_ref(write_tokens(p));
 
1182
            break;
 
1183
        case pdf_literal_node:
 
1184
            if (pdf_literal_type(p) == normal)
 
1185
                check_token_ref(pdf_literal_data(p));
 
1186
            break;
 
1187
        case pdf_colorstack_node:
 
1188
            if (pdf_colorstack_cmd(p) <= colorstack_data)
 
1189
                check_token_ref(pdf_colorstack_data(p));
 
1190
            break;
 
1191
        case pdf_setmatrix_node:
 
1192
            check_token_ref(pdf_setmatrix_data(p));
 
1193
            break;
 
1194
        case late_lua_node:
 
1195
            if (late_lua_name(p) > 0)
 
1196
                check_token_ref(late_lua_name(p));
 
1197
            check_token_ref(late_lua_data(p));
 
1198
            break;
 
1199
        case pdf_annot_node:
 
1200
            check_token_ref(pdf_annot_data(p));
 
1201
            break;
 
1202
        case pdf_start_link_node:
 
1203
            if (pdf_link_attr(p) != null)
 
1204
                check_token_ref(pdf_link_attr(p));
 
1205
            check_action_ref(pdf_link_action(p));
 
1206
            break;
 
1207
        case pdf_dest_node:
 
1208
            if (pdf_dest_named_id(p) > 0)
 
1209
                check_token_ref(pdf_dest_id(p));
 
1210
            break;
 
1211
        case pdf_thread_node:
 
1212
        case pdf_start_thread_node:
 
1213
            if (pdf_thread_named_id(p) > 0)
 
1214
                check_token_ref(pdf_thread_id(p));
 
1215
            if (pdf_thread_attr(p) != null)
 
1216
                check_token_ref(pdf_thread_attr(p));
 
1217
            break;
 
1218
        case user_defined_node:
 
1219
            switch (user_node_type(p)) {
 
1220
            case 'a':
 
1221
                check_attribute_ref(user_node_value(p));
 
1222
                break;
 
1223
            case 't':
 
1224
                check_token_ref(user_node_value(p));
 
1225
                break;
 
1226
            case 'n':
 
1227
                dorangetest(p, user_node_value(p), var_mem_max);
 
1228
                break;
 
1229
            case 's':
 
1230
            case 'd':
 
1231
                break;
 
1232
            default:
 
1233
                confusion("extuser");
 
1234
                break;
 
1235
            }
 
1236
            break;
 
1237
        case dir_node:
 
1238
        case open_node:
 
1239
        case write_node:
 
1240
        case close_node:
 
1241
        case pdf_save_node:
 
1242
        case pdf_restore_node:
 
1243
        case cancel_boundary_node:
 
1244
        case close_lua_node:
 
1245
        case pdf_refobj_node:
 
1246
        case pdf_refxform_node:
 
1247
        case pdf_refximage_node:
 
1248
        case pdf_end_link_node:
 
1249
        case pdf_end_thread_node:
 
1250
        case pdf_save_pos_node:
 
1251
        case local_par_node:
 
1252
            break;
 
1253
        default:
 
1254
            confusion("ext3");
 
1255
        }
 
1256
        break;
 
1257
    case margin_kern_node:
 
1258
        check_node(margin_char(p));
 
1259
        break;
 
1260
    case disc_node:
 
1261
        dorangetest(p, vlink(pre_break(p)), var_mem_max);
 
1262
        dorangetest(p, vlink(post_break(p)), var_mem_max);
 
1263
        dorangetest(p, vlink(no_break(p)), var_mem_max);
 
1264
        break;
 
1265
    case adjust_node:
 
1266
        dorangetest(p, adjust_ptr(p), var_mem_max);
 
1267
        break;
 
1268
    case pseudo_file_node:
 
1269
        dorangetest(p, pseudo_lines(p), var_mem_max);
 
1270
        break;
 
1271
    case pseudo_line_node:
 
1272
    case shape_node:
 
1273
        break;
 
1274
    case choice_node:
 
1275
        dorangetest(p, display_mlist(p), var_mem_max);
 
1276
        dorangetest(p, text_mlist(p), var_mem_max);
 
1277
        dorangetest(p, script_mlist(p), var_mem_max);
 
1278
        dorangetest(p, script_script_mlist(p), var_mem_max);
 
1279
        break;
 
1280
    case fraction_noad:
 
1281
        dorangetest(p, numerator(p), var_mem_max);
 
1282
        dorangetest(p, denominator(p), var_mem_max);
 
1283
        dorangetest(p, left_delimiter(p), var_mem_max);
 
1284
        dorangetest(p, right_delimiter(p), var_mem_max);
 
1285
        break;
 
1286
    case simple_noad:
 
1287
        dorangetest(p, nucleus(p), var_mem_max);
 
1288
        dorangetest(p, subscr(p), var_mem_max);
 
1289
        dorangetest(p, supscr(p), var_mem_max);
 
1290
        break;
 
1291
    case radical_noad:
 
1292
        dorangetest(p, nucleus(p), var_mem_max);
 
1293
        dorangetest(p, subscr(p), var_mem_max);
 
1294
        dorangetest(p, supscr(p), var_mem_max);
 
1295
        dorangetest(p, degree(p), var_mem_max);
 
1296
        dorangetest(p, left_delimiter(p), var_mem_max);
 
1297
        break;
 
1298
    case accent_noad:
 
1299
        dorangetest(p, nucleus(p), var_mem_max);
 
1300
        dorangetest(p, subscr(p), var_mem_max);
 
1301
        dorangetest(p, supscr(p), var_mem_max);
 
1302
        dorangetest(p, accent_chr(p), var_mem_max);
 
1303
        dorangetest(p, bot_accent_chr(p), var_mem_max);
 
1304
        break;
 
1305
    case fence_noad:
 
1306
        dorangetest(p, delimiter(p), var_mem_max);
 
1307
        break;
 
1308
    case rule_node:
 
1309
    case kern_node:
 
1310
    case math_node:
 
1311
    case penalty_node:
 
1312
    case mark_node:
 
1313
    case style_node:
 
1314
    case attribute_list_node:
 
1315
    case attribute_node:
 
1316
    case glue_spec_node:
 
1317
    case temp_node:
 
1318
    case align_stack_node:
 
1319
    case movement_node:
 
1320
    case if_node:
 
1321
    case nesting_node:
 
1322
    case span_node:
 
1323
    case unhyphenated_node:
 
1324
    case hyphenated_node:
 
1325
    case delta_node:
 
1326
    case passive_node:
 
1327
    case expr_node:
 
1328
        break;
 
1329
    default:
 
1330
        fprintf(stdout, "check_node: type is %d\n", type(p));
 
1331
    }
 
1332
}
 
1333
 
 
1334
@ @c
 
1335
static void check_static_node_mem(void)
 
1336
{
 
1337
    dotest(zero_glue, width(zero_glue), 0);
 
1338
    dotest(zero_glue, type(zero_glue), glue_spec_node);
 
1339
    dotest(zero_glue, vlink(zero_glue), null);
 
1340
    dotest(zero_glue, stretch(zero_glue), 0);
 
1341
    dotest(zero_glue, stretch_order(zero_glue), normal);
 
1342
    dotest(zero_glue, shrink(zero_glue), 0);
 
1343
    dotest(zero_glue, shrink_order(zero_glue), normal);
 
1344
 
 
1345
    dotest(sfi_glue, width(sfi_glue), 0);
 
1346
    dotest(sfi_glue, type(sfi_glue), glue_spec_node);
 
1347
    dotest(sfi_glue, vlink(sfi_glue), null);
 
1348
    dotest(sfi_glue, stretch(sfi_glue), 0);
 
1349
    dotest(sfi_glue, stretch_order(sfi_glue), sfi);
 
1350
    dotest(sfi_glue, shrink(sfi_glue), 0);
 
1351
    dotest(sfi_glue, shrink_order(sfi_glue), normal);
 
1352
 
 
1353
    dotest(fil_glue, width(fil_glue), 0);
 
1354
    dotest(fil_glue, type(fil_glue), glue_spec_node);
 
1355
    dotest(fil_glue, vlink(fil_glue), null);
 
1356
    dotest(fil_glue, stretch(fil_glue), unity);
 
1357
    dotest(fil_glue, stretch_order(fil_glue), fil);
 
1358
    dotest(fil_glue, shrink(fil_glue), 0);
 
1359
    dotest(fil_glue, shrink_order(fil_glue), normal);
 
1360
 
 
1361
    dotest(fill_glue, width(fill_glue), 0);
 
1362
    dotest(fill_glue, type(fill_glue), glue_spec_node);
 
1363
    dotest(fill_glue, vlink(fill_glue), null);
 
1364
    dotest(fill_glue, stretch(fill_glue), unity);
 
1365
    dotest(fill_glue, stretch_order(fill_glue), fill);
 
1366
    dotest(fill_glue, shrink(fill_glue), 0);
 
1367
    dotest(fill_glue, shrink_order(fill_glue), normal);
 
1368
 
 
1369
    dotest(ss_glue, width(ss_glue), 0);
 
1370
    dotest(ss_glue, type(ss_glue), glue_spec_node);
 
1371
    dotest(ss_glue, vlink(ss_glue), null);
 
1372
    dotest(ss_glue, stretch(ss_glue), unity);
 
1373
    dotest(ss_glue, stretch_order(ss_glue), fil);
 
1374
    dotest(ss_glue, shrink(ss_glue), unity);
 
1375
    dotest(ss_glue, shrink_order(ss_glue), fil);
 
1376
 
 
1377
    dotest(fil_neg_glue, width(fil_neg_glue), 0);
 
1378
    dotest(fil_neg_glue, type(fil_neg_glue), glue_spec_node);
 
1379
    dotest(fil_neg_glue, vlink(fil_neg_glue), null);
 
1380
    dotest(fil_neg_glue, stretch(fil_neg_glue), -unity);
 
1381
    dotest(fil_neg_glue, stretch_order(fil_neg_glue), fil);
 
1382
    dotest(fil_neg_glue, shrink(fil_neg_glue), 0);
 
1383
    dotest(fil_neg_glue, shrink_order(fil_neg_glue), normal);
 
1384
}
 
1385
 
 
1386
@ @c
 
1387
void check_node_mem(void)
 
1388
{
 
1389
    int i;
 
1390
    check_static_node_mem();
 
1391
#ifndef NDEBUG
 
1392
    for (i = (my_prealloc + 1); i < var_mem_max; i++) {
 
1393
        if (varmem_sizes[i] > 0) {
 
1394
            check_node(i);
 
1395
        }
 
1396
    }
 
1397
#endif
 
1398
    test_count++;
 
1399
}
 
1400
 
 
1401
@ @c
 
1402
void fix_node_list(halfword head)
 
1403
{
 
1404
    halfword p, q;
 
1405
    if (head == null)
 
1406
        return;
 
1407
    p = head;
 
1408
    q = vlink(p);
 
1409
    while (q != null) {
 
1410
        alink(q) = p;
 
1411
        p = q;
 
1412
        q = vlink(p);
 
1413
    }
 
1414
}
 
1415
 
 
1416
@ @c
 
1417
halfword get_node(int s)
 
1418
{
 
1419
    register halfword r;
 
1420
#if 0
 
1421
    check_static_node_mem(); 
 
1422
#endif
 
1423
    assert(s < MAX_CHAIN_SIZE);
 
1424
 
 
1425
    r = free_chain[s];
 
1426
    if (r != null) {
 
1427
        free_chain[s] = vlink(r);
 
1428
#ifndef NDEBUG
 
1429
        varmem_sizes[r] = (char) s;
 
1430
#endif
 
1431
        vlink(r) = null;
 
1432
        var_used += s;          /* maintain usage statistics */
 
1433
        return r;
 
1434
    }
 
1435
    /* this is the end of the 'inner loop' */
 
1436
    return slow_get_node(s);
 
1437
}
 
1438
 
 
1439
@ @c
 
1440
#ifdef DEBUG
 
1441
static void print_free_chain(int c)
 
1442
{
 
1443
    halfword p = free_chain[c];
 
1444
    fprintf(stdout, "\nfree chain[%d] =\n  ", c);
 
1445
    while (p != null) {
 
1446
        fprintf(stdout, "%d,", (int) p);
 
1447
        p = vlink(p);
 
1448
    }
 
1449
    fprintf(stdout, "null;\n");
 
1450
}
 
1451
#endif
 
1452
 
 
1453
@ @c
 
1454
void free_node(halfword p, int s)
 
1455
{
 
1456
 
 
1457
    if (p <= my_prealloc) {
 
1458
        fprintf(stdout, "node %d (type %d) should not be freed!\n", (int) p,
 
1459
                type(p));
 
1460
        return;
 
1461
    }
 
1462
#ifndef NDEBUG
 
1463
    varmem_sizes[p] = 0;
 
1464
#endif
 
1465
    if (s < MAX_CHAIN_SIZE) {
 
1466
        vlink(p) = free_chain[s];
 
1467
        free_chain[s] = p;
 
1468
    } else {
 
1469
        /* todo ? it is perhaps possible to merge this node with an existing rover */
 
1470
        node_size(p) = s;
 
1471
        vlink(p) = rover;
 
1472
        while (vlink(rover) != vlink(p)) {
 
1473
            rover = vlink(rover);
 
1474
        }
 
1475
        vlink(rover) = p;
 
1476
    }
 
1477
    var_used -= s;              /* maintain statistics */
 
1478
}
 
1479
 
 
1480
@ @c
 
1481
static void free_node_chain(halfword q, int s)
 
1482
{
 
1483
    register halfword p = q;
 
1484
    while (vlink(p) != null) {
 
1485
#ifndef NDEBUG
 
1486
        varmem_sizes[p] = 0;
 
1487
#endif
 
1488
        var_used -= s;
 
1489
        p = vlink(p);
 
1490
    }
 
1491
    var_used -= s;
 
1492
#ifndef NDEBUG
 
1493
    varmem_sizes[p] = 0;
 
1494
#endif
 
1495
    vlink(p) = free_chain[s];
 
1496
    free_chain[s] = q;
 
1497
}
 
1498
 
 
1499
 
 
1500
@ @c
 
1501
void init_node_mem(int t)
 
1502
{
 
1503
    my_prealloc = var_mem_stat_max;
 
1504
    assert(whatsit_node_data[user_defined_node].id == user_defined_node);
 
1505
    assert(node_data[passive_node].id == passive_node);
 
1506
 
 
1507
    varmem =
 
1508
        (memory_word *) realloc((void *) varmem,
 
1509
                                sizeof(memory_word) * (unsigned) t);
 
1510
    if (varmem == NULL) {
 
1511
        overflow("node memory size", (unsigned) var_mem_max);
 
1512
    }
 
1513
    memset((void *) (varmem), 0, (unsigned) t * sizeof(memory_word));
 
1514
 
 
1515
#ifndef NDEBUG
 
1516
    varmem_sizes = (char *) realloc(varmem_sizes, sizeof(char) * (unsigned) t);
 
1517
    if (varmem_sizes == NULL) {
 
1518
        overflow("node memory size", (unsigned) var_mem_max);
 
1519
    }
 
1520
    memset((void *) varmem_sizes, 0, sizeof(char) * (unsigned) t);
 
1521
#endif
 
1522
    var_mem_max = t;
 
1523
    rover = var_mem_stat_max + 1;
 
1524
    vlink(rover) = rover;
 
1525
    node_size(rover) = (t - rover);
 
1526
    var_used = 0;
 
1527
    /* initialize static glue specs */
 
1528
    glue_ref_count(zero_glue) = null + 1;
 
1529
    width(zero_glue) = 0;
 
1530
    type(zero_glue) = glue_spec_node;
 
1531
    vlink(zero_glue) = null;
 
1532
    stretch(zero_glue) = 0;
 
1533
    stretch_order(zero_glue) = normal;
 
1534
    shrink(zero_glue) = 0;
 
1535
    shrink_order(zero_glue) = normal;
 
1536
    glue_ref_count(sfi_glue) = null + 1;
 
1537
    width(sfi_glue) = 0;
 
1538
    type(sfi_glue) = glue_spec_node;
 
1539
    vlink(sfi_glue) = null;
 
1540
    stretch(sfi_glue) = 0;
 
1541
    stretch_order(sfi_glue) = sfi;
 
1542
    shrink(sfi_glue) = 0;
 
1543
    shrink_order(sfi_glue) = normal;
 
1544
    glue_ref_count(fil_glue) = null + 1;
 
1545
    width(fil_glue) = 0;
 
1546
    type(fil_glue) = glue_spec_node;
 
1547
    vlink(fil_glue) = null;
 
1548
    stretch(fil_glue) = unity;
 
1549
    stretch_order(fil_glue) = fil;
 
1550
    shrink(fil_glue) = 0;
 
1551
    shrink_order(fil_glue) = normal;
 
1552
    glue_ref_count(fill_glue) = null + 1;
 
1553
    width(fill_glue) = 0;
 
1554
    type(fill_glue) = glue_spec_node;
 
1555
    vlink(fill_glue) = null;
 
1556
    stretch(fill_glue) = unity;
 
1557
    stretch_order(fill_glue) = fill;
 
1558
    shrink(fill_glue) = 0;
 
1559
    shrink_order(fill_glue) = normal;
 
1560
    glue_ref_count(ss_glue) = null + 1;
 
1561
    width(ss_glue) = 0;
 
1562
    type(ss_glue) = glue_spec_node;
 
1563
    vlink(ss_glue) = null;
 
1564
    stretch(ss_glue) = unity;
 
1565
    stretch_order(ss_glue) = fil;
 
1566
    shrink(ss_glue) = unity;
 
1567
    shrink_order(ss_glue) = fil;
 
1568
    glue_ref_count(fil_neg_glue) = null + 1;
 
1569
    width(fil_neg_glue) = 0;
 
1570
    type(fil_neg_glue) = glue_spec_node;
 
1571
    vlink(fil_neg_glue) = null;
 
1572
    stretch(fil_neg_glue) = -unity;
 
1573
    stretch_order(fil_neg_glue) = fil;
 
1574
    shrink(fil_neg_glue) = 0;
 
1575
    shrink_order(fil_neg_glue) = normal;
 
1576
    /* initialize node list heads */
 
1577
    vinfo(page_ins_head) = 0;
 
1578
    vlink(page_ins_head) = null;
 
1579
    alink(page_ins_head) = null;
 
1580
    vinfo(contrib_head) = 0;
 
1581
    vlink(contrib_head) = null;
 
1582
    alink(contrib_head) = null;
 
1583
    vinfo(page_head) = 0;
 
1584
    vlink(page_head) = null;
 
1585
    alink(page_head) = null;
 
1586
    vinfo(temp_head) = 0;
 
1587
    vlink(temp_head) = null;
 
1588
    alink(temp_head) = null;
 
1589
    vinfo(hold_head) = 0;
 
1590
    vlink(hold_head) = null;
 
1591
    alink(hold_head) = null;
 
1592
    vinfo(adjust_head) = 0;
 
1593
    vlink(adjust_head) = null;
 
1594
    alink(adjust_head) = null;
 
1595
    vinfo(pre_adjust_head) = 0;
 
1596
    vlink(pre_adjust_head) = null;
 
1597
    alink(pre_adjust_head) = null;
 
1598
    vinfo(active) = 0;
 
1599
    vlink(active) = null;
 
1600
    alink(active) = null;
 
1601
    vinfo(align_head) = 0;
 
1602
    vlink(align_head) = null;
 
1603
    alink(align_head) = null;
 
1604
    vinfo(end_span) = 0;
 
1605
    vlink(end_span) = null;
 
1606
    alink(end_span) = null;
 
1607
    type(begin_point) = glyph_node;
 
1608
    subtype(begin_point) = 0;
 
1609
    vlink(begin_point) = null;
 
1610
    vinfo(begin_point + 1) = null;
 
1611
    alink(begin_point) = null;
 
1612
    font(begin_point) = 0;
 
1613
    character(begin_point) = '.';
 
1614
    vinfo(begin_point + 3) = 0;
 
1615
    vlink(begin_point + 3) = 0;
 
1616
    vinfo(begin_point + 4) = 0;
 
1617
    vlink(begin_point + 4) = 0;
 
1618
    type(end_point) = glyph_node;
 
1619
    subtype(end_point) = 0;
 
1620
    vlink(end_point) = null;
 
1621
    vinfo(end_point + 1) = null;
 
1622
    alink(end_point) = null;
 
1623
    font(end_point) = 0;
 
1624
    character(end_point) = '.';
 
1625
    vinfo(end_point + 3) = 0;
 
1626
    vlink(end_point + 3) = 0;
 
1627
    vinfo(end_point + 4) = 0;
 
1628
    vlink(end_point + 4) = 0;
 
1629
}
 
1630
 
 
1631
@ @c
 
1632
void dump_node_mem(void)
 
1633
{
 
1634
    dump_int(var_mem_max);
 
1635
    dump_int(rover);
 
1636
    dump_things(varmem[0], var_mem_max);
 
1637
#ifndef NDEBUG
 
1638
    dump_things(varmem_sizes[0], var_mem_max);
 
1639
#endif
 
1640
    dump_things(free_chain[0], MAX_CHAIN_SIZE);
 
1641
    dump_int(var_used);
 
1642
    dump_int(my_prealloc);
 
1643
}
 
1644
 
 
1645
@ it makes sense to enlarge the varmem array immediately
 
1646
@c
 
1647
void undump_node_mem(void)
 
1648
{
 
1649
    int x;
 
1650
    undump_int(x);
 
1651
    undump_int(rover);
 
1652
    var_mem_max = (x < 100000 ? 100000 : x);
 
1653
    varmem = xmallocarray(memory_word, (unsigned) var_mem_max);
 
1654
#if 0
 
1655
    memset ((void *)varmem,0,x*sizeof(memory_word));
 
1656
#endif
 
1657
    undump_things(varmem[0], x);
 
1658
#ifndef NDEBUG
 
1659
    varmem_sizes = xmallocarray(char, (unsigned) var_mem_max);
 
1660
    memset((void *) varmem_sizes, 0, (unsigned) var_mem_max * sizeof(char));
 
1661
    undump_things(varmem_sizes[0], x);
 
1662
#endif
 
1663
    undump_things(free_chain[0], MAX_CHAIN_SIZE);
 
1664
    undump_int(var_used);
 
1665
    undump_int(my_prealloc);
 
1666
    if (var_mem_max > x) {
 
1667
        /* todo ? it is perhaps possible to merge the new node with an existing rover */
 
1668
        vlink(x) = rover;
 
1669
        node_size(x) = (var_mem_max - x);
 
1670
        while (vlink(rover) != vlink(x)) {
 
1671
            rover = vlink(rover);
 
1672
        }
 
1673
        vlink(rover) = x;
 
1674
    }
 
1675
}
 
1676
 
 
1677
#if 0
 
1678
void test_rovers(char *s)
 
1679
{
 
1680
    int q = rover;
 
1681
    int r = q;
 
1682
    fprintf(stdout, "%s: {rover=%d,size=%d,link=%d}", s, r, node_size(r),
 
1683
            vlink(r));
 
1684
    while (vlink(r) != q) {
 
1685
        r = vlink(r);
 
1686
        fprintf(stdout, ",{rover=%d,size=%d,link=%d}", r, node_size(r),
 
1687
                vlink(r));
 
1688
    }
 
1689
    fprintf(stdout, "\n");
 
1690
}
 
1691
#else
 
1692
#  define test_rovers(a)
 
1693
#endif
 
1694
 
 
1695
@ @c
 
1696
halfword slow_get_node(int s)
 
1697
{
 
1698
    register int t;
 
1699
 
 
1700
  RETRY:
 
1701
    t = node_size(rover);
 
1702
    assert(vlink(rover) < var_mem_max);
 
1703
    assert(vlink(rover) != 0);
 
1704
    test_rovers("entry");
 
1705
    if (t > s) {
 
1706
        register halfword r;
 
1707
        /* allocating from the bottom helps decrease page faults */
 
1708
        r = rover;
 
1709
        rover += s;
 
1710
        vlink(rover) = vlink(r);
 
1711
        node_size(rover) = node_size(r) - s;
 
1712
        if (vlink(rover) != r) {        /* list is longer than one */
 
1713
            halfword q = r;
 
1714
            while (vlink(q) != r) {
 
1715
                q = vlink(q);
 
1716
            }
 
1717
            vlink(q) += s;
 
1718
        } else {
 
1719
            vlink(rover) += s;
 
1720
        }
 
1721
        test_rovers("taken");
 
1722
        assert(vlink(rover) < var_mem_max);
 
1723
#ifndef NDEBUG
 
1724
        varmem_sizes[r] = (char) (s > 127 ? 127 : s);
 
1725
#endif
 
1726
        vlink(r) = null;
 
1727
        var_used += s;          /* maintain usage statistics */
 
1728
        return r;               /* this is the only exit */
 
1729
    } else {
 
1730
        int x;
 
1731
        /* attempt to keep the free list small */
 
1732
        if (vlink(rover) != rover) {
 
1733
            if (t < MAX_CHAIN_SIZE) {
 
1734
                halfword l = vlink(rover);
 
1735
                vlink(rover) = free_chain[t];
 
1736
                free_chain[t] = rover;
 
1737
                rover = l;
 
1738
                while (vlink(l) != free_chain[t]) {
 
1739
                    l = vlink(l);
 
1740
                }
 
1741
                vlink(l) = rover;
 
1742
                test_rovers("outtake");
 
1743
                goto RETRY;
 
1744
            } else {
 
1745
                halfword l = rover;
 
1746
                while (vlink(rover) != l) {
 
1747
                    if (node_size(rover) > s) {
 
1748
                        goto RETRY;
 
1749
                    }
 
1750
                    rover = vlink(rover);
 
1751
                }
 
1752
            }
 
1753
        }
 
1754
        /* if we are still here, it was apparently impossible to get a match */
 
1755
        x = (var_mem_max >> 2) + s;
 
1756
        varmem =
 
1757
            (memory_word *) realloc((void *) varmem,
 
1758
                                    sizeof(memory_word) *
 
1759
                                    (unsigned) (var_mem_max + x));
 
1760
        if (varmem == NULL) {
 
1761
            overflow("node memory size", (unsigned) var_mem_max);
 
1762
        }
 
1763
        memset((void *) (varmem + var_mem_max), 0,
 
1764
               (unsigned) x * sizeof(memory_word));
 
1765
 
 
1766
#ifndef NDEBUG
 
1767
        varmem_sizes =
 
1768
            (char *) realloc(varmem_sizes,
 
1769
                             sizeof(char) * (unsigned) (var_mem_max + x));
 
1770
        if (varmem_sizes == NULL) {
 
1771
            overflow("node memory size", (unsigned) var_mem_max);
 
1772
        }
 
1773
        memset((void *) (varmem_sizes + var_mem_max), 0,
 
1774
               (unsigned) (x) * sizeof(char));
 
1775
#endif
 
1776
 
 
1777
        /* todo ? it is perhaps possible to merge the new memory with an existing rover */
 
1778
        vlink(var_mem_max) = rover;
 
1779
        node_size(var_mem_max) = x;
 
1780
        while (vlink(rover) != vlink(var_mem_max)) {
 
1781
            rover = vlink(rover);
 
1782
        }
 
1783
        vlink(rover) = var_mem_max;
 
1784
        rover = var_mem_max;
 
1785
        test_rovers("realloc");
 
1786
        var_mem_max += x;
 
1787
        goto RETRY;
 
1788
    }
 
1789
}
 
1790
 
 
1791
@ @c
 
1792
char *sprint_node_mem_usage(void)
 
1793
{
 
1794
    int i, b;
 
1795
 
 
1796
    char *s, *ss;
 
1797
#ifndef NDEBUG
 
1798
    char msg[256];
 
1799
    int node_counts[last_normal_node + last_whatsit_node + 2] = { 0 };
 
1800
 
 
1801
    for (i = (var_mem_max - 1); i > my_prealloc; i--) {
 
1802
        if (varmem_sizes[i] > 0) {
 
1803
            if (type(i) > last_normal_node + last_whatsit_node) {
 
1804
                node_counts[last_normal_node + last_whatsit_node + 1]++;
 
1805
            } else if (type(i) == whatsit_node) {
 
1806
                node_counts[(subtype(i) + last_normal_node + 1)]++;
 
1807
            } else {
 
1808
                node_counts[type(i)]++;
 
1809
            }
 
1810
        }
 
1811
    }
 
1812
    s = strdup("");
 
1813
    b = 0;
 
1814
    for (i = 0; i < last_normal_node + last_whatsit_node + 2; i++) {
 
1815
        if (node_counts[i] > 0) {
 
1816
            int j =
 
1817
                (i > (last_normal_node + 1) ? (i - last_normal_node - 1) : 0);
 
1818
            snprintf(msg, 255, "%s%d %s", (b ? ", " : ""), (int) node_counts[i],
 
1819
                     get_node_name((i > last_normal_node ? whatsit_node : i),
 
1820
                                   j));
 
1821
            ss = xmalloc((unsigned) (strlen(s) + strlen(msg) + 1));
 
1822
            strcpy(ss, s);
 
1823
            strcat(ss, msg);
 
1824
            free(s);
 
1825
            s = ss;
 
1826
            b = 1;
 
1827
        }
 
1828
    }
 
1829
#else
 
1830
    s = strdup("");
 
1831
#endif
 
1832
    return s;
 
1833
}
 
1834
 
 
1835
@ @c
 
1836
halfword list_node_mem_usage(void)
 
1837
{
 
1838
    halfword i, j;
 
1839
    halfword p = null, q = null;
 
1840
#ifndef NDEBUG
 
1841
    char *saved_varmem_sizes = xmallocarray(char, (unsigned) var_mem_max);
 
1842
    memcpy(saved_varmem_sizes, varmem_sizes, (size_t) var_mem_max);
 
1843
    for (i = my_prealloc + 1; i < (var_mem_max - 1); i++) {
 
1844
        if (saved_varmem_sizes[i] > 0) {
 
1845
            j = copy_node(i);
 
1846
            if (p == null) {
 
1847
                q = j;
 
1848
            } else {
 
1849
                vlink(p) = j;
 
1850
            }
 
1851
            p = j;
 
1852
        }
 
1853
    }
 
1854
    free(saved_varmem_sizes);
 
1855
#endif
 
1856
    return q;
 
1857
}
 
1858
 
 
1859
@ @c
 
1860
void print_node_mem_stats(void)
 
1861
{
 
1862
    int i, b;
 
1863
    halfword j;
 
1864
    char msg[256];
 
1865
    char *s;
 
1866
    int free_chain_counts[MAX_CHAIN_SIZE] = { 0 };
 
1867
    snprintf(msg, 255, " %d words of node memory still in use:",
 
1868
             (int) (var_used + my_prealloc));
 
1869
    tprint_nl(msg);
 
1870
    s = sprint_node_mem_usage();
 
1871
    tprint_nl("   ");
 
1872
    tprint(s);
 
1873
    free(s);
 
1874
    tprint(" nodes");
 
1875
    tprint_nl("   avail lists: ");
 
1876
    b = 0;
 
1877
    for (i = 1; i < MAX_CHAIN_SIZE; i++) {
 
1878
        for (j = free_chain[i]; j != null; j = vlink(j))
 
1879
            free_chain_counts[i]++;
 
1880
        if (free_chain_counts[i] > 0) {
 
1881
            snprintf(msg, 255, "%s%d:%d", (b ? "," : ""), i,
 
1882
                     (int) free_chain_counts[i]);
 
1883
            tprint(msg);
 
1884
            b = 1;
 
1885
        }
 
1886
    }
 
1887
    print_nlp();                /* newline, if needed */
 
1888
}
 
1889
 
 
1890
/* this belongs in the web but i couldn't find the correct syntactic place */
 
1891
 
 
1892
halfword new_span_node(halfword n, int s, scaled w)
 
1893
{
 
1894
    halfword p = new_node(span_node, 0);
 
1895
    span_link(p) = n;
 
1896
    span_span(p) = s;
 
1897
    width(p) = w;
 
1898
    return p;
 
1899
}
 
1900
 
 
1901
@* Attribute stuff.
 
1902
 
 
1903
@c
 
1904
static halfword new_attribute_node(unsigned int i, int v)
 
1905
{
 
1906
    register halfword r = get_node(attribute_node_size);
 
1907
    type(r) = attribute_node;
 
1908
    attribute_id(r) = (halfword) i;
 
1909
    attribute_value(r) = v;
 
1910
    return r;
 
1911
}
 
1912
 
 
1913
@ @c
 
1914
halfword copy_attribute_list(halfword n)
 
1915
{
 
1916
    halfword q = get_node(attribute_node_size);
 
1917
    register halfword p = q;
 
1918
    type(p) = attribute_list_node;
 
1919
    attr_list_ref(p) = 0;
 
1920
    n = vlink(n);
 
1921
    while (n != null) {
 
1922
        register halfword r = get_node(attribute_node_size);
 
1923
        /* the link will be fixed automatically in the next loop */
 
1924
        (void) memcpy((void *) (varmem + r), (void *) (varmem + n),
 
1925
                      (sizeof(memory_word) * attribute_node_size));
 
1926
        vlink(p) = r;
 
1927
        p = r;
 
1928
        n = vlink(n);
 
1929
    }
 
1930
    return q;
 
1931
}
 
1932
 
 
1933
@ @c
 
1934
void update_attribute_cache(void)
 
1935
{
 
1936
    halfword p;
 
1937
    register int i;
 
1938
    attr_list_cache = get_node(attribute_node_size);
 
1939
    type(attr_list_cache) = attribute_list_node;
 
1940
    attr_list_ref(attr_list_cache) = 0;
 
1941
    p = attr_list_cache;
 
1942
    for (i = 0; i <= max_used_attr; i++) {
 
1943
        register int v = attribute(i);
 
1944
        if (v > UNUSED_ATTRIBUTE) {
 
1945
            register halfword r = new_attribute_node((unsigned) i, v);
 
1946
            vlink(p) = r;
 
1947
            p = r;
 
1948
        }
 
1949
    }
 
1950
    if (vlink(attr_list_cache) == null) {
 
1951
        free_node(attr_list_cache, attribute_node_size);
 
1952
        attr_list_cache = null;
 
1953
    }
 
1954
    return;
 
1955
}
 
1956
 
 
1957
@ @c
 
1958
void build_attribute_list(halfword b)
 
1959
{
 
1960
    if (max_used_attr >= 0) {
 
1961
        if (attr_list_cache == cache_disabled) {
 
1962
            update_attribute_cache();
 
1963
            if (attr_list_cache == null)
 
1964
                return;
 
1965
        }
 
1966
        attr_list_ref(attr_list_cache)++;
 
1967
        node_attr(b) = attr_list_cache;
 
1968
#ifdef DEBUG
 
1969
        fprintf(DEBUG_OUT, "Added attrlist (%d) to node %d (count=%d)\n",
 
1970
                node_attr(b), b, attr_list_ref(attr_list_cache));
 
1971
#endif
 
1972
    }
 
1973
}
 
1974
 
 
1975
@ @c
 
1976
void delete_attribute_ref(halfword b)
 
1977
{
 
1978
    if (b != null) {
 
1979
        assert(type(b) == attribute_list_node);
 
1980
        attr_list_ref(b)--;
 
1981
#ifdef DEBUG
 
1982
        fprintf(DEBUG_OUT, "Removed attrlistref (%d) (count=%d)\n", b,
 
1983
                attr_list_ref(b));
 
1984
#endif
 
1985
        if (attr_list_ref(b) == 0) {
 
1986
            if (b == attr_list_cache)
 
1987
                attr_list_cache = cache_disabled;
 
1988
            free_node_chain(b, attribute_node_size);
 
1989
        }
 
1990
        /* maintain sanity */
 
1991
        if (attr_list_ref(b) < 0)
 
1992
            attr_list_ref(b) = 0;
 
1993
    }
 
1994
}
 
1995
 
 
1996
@ |p| is an attr list head, or zero
 
1997
@c
 
1998
halfword do_set_attribute(halfword p, int i, int val)
 
1999
{
 
2000
    register halfword q;
 
2001
    register int j = 0;
 
2002
    if (p == null) {            /* add a new head \& node */
 
2003
        q = get_node(attribute_node_size);
 
2004
        type(q) = attribute_list_node;
 
2005
        attr_list_ref(q) = 1;
 
2006
        p = new_attribute_node((unsigned) i, val);
 
2007
        vlink(q) = p;
 
2008
        return q;
 
2009
    }
 
2010
    q = p;
 
2011
    assert(vlink(p) != null);
 
2012
    while (vlink(p) != null) {
 
2013
        int t = attribute_id(vlink(p));
 
2014
        if (t == i && attribute_value(vlink(p)) == val)
 
2015
            return q;           /* no need to do anything */
 
2016
        if (t >= i)
 
2017
            break;
 
2018
        j++;
 
2019
        p = vlink(p);
 
2020
    }
 
2021
 
 
2022
    p = q;
 
2023
    while (j-- > 0)
 
2024
        p = vlink(p);
 
2025
    if (attribute_id(vlink(p)) == i) {
 
2026
        attribute_value(vlink(p)) = val;
 
2027
    } else {                    /* add a new node */
 
2028
        halfword r = new_attribute_node((unsigned) i, val);
 
2029
        vlink(r) = vlink(p);
 
2030
        vlink(p) = r;
 
2031
    }
 
2032
    return q;
 
2033
}
 
2034
 
 
2035
@ @c
 
2036
void set_attribute(halfword n, int i, int val)
 
2037
{
 
2038
    register halfword p;
 
2039
    register int j = 0;
 
2040
    if (!nodetype_has_attributes(type(n)))
 
2041
        return;
 
2042
    p = node_attr(n);
 
2043
    if (p == null) {            /* add a new head \& node */
 
2044
        p = get_node(attribute_node_size);
 
2045
        type(p) = attribute_list_node;
 
2046
        attr_list_ref(p) = 1;
 
2047
        node_attr(n) = p;
 
2048
        p = new_attribute_node((unsigned) i, val);
 
2049
        vlink(node_attr(n)) = p;
 
2050
        return;
 
2051
    }
 
2052
    assert(vlink(p) != null);
 
2053
    while (vlink(p) != null) {
 
2054
        int t = attribute_id(vlink(p));
 
2055
        if (t == i && attribute_value(vlink(p)) == val)
 
2056
            return;
 
2057
        if (t >= i)
 
2058
            break;
 
2059
        j++;
 
2060
        p = vlink(p);
 
2061
    }
 
2062
    p = node_attr(n);
 
2063
    if (attr_list_ref(p) != 1) {
 
2064
        if (attr_list_ref(p) > 1) {
 
2065
            p = copy_attribute_list(p);
 
2066
            delete_attribute_ref(node_attr(n));
 
2067
            node_attr(n) = p;
 
2068
        } else {
 
2069
            fprintf(stdout,
 
2070
                    "Node %d has an attribute list that is free already\n",
 
2071
                    (int) n);
 
2072
        }
 
2073
        attr_list_ref(p) = 1;
 
2074
    }
 
2075
    while (j-- > 0)
 
2076
        p = vlink(p);
 
2077
 
 
2078
    if (attribute_id(vlink(p)) == i) {
 
2079
        attribute_value(vlink(p)) = val;
 
2080
    } else {                    /* add a new node */
 
2081
        halfword r = new_attribute_node((unsigned) i, val);
 
2082
        vlink(r) = vlink(p);
 
2083
        vlink(p) = r;
 
2084
    }
 
2085
    return;
 
2086
}
 
2087
 
 
2088
 
 
2089
@ @c
 
2090
int unset_attribute(halfword n, int i, int val)
 
2091
{
 
2092
    register halfword p;
 
2093
    register int t;
 
2094
    register int j = 0;
 
2095
 
 
2096
    if (!nodetype_has_attributes(type(n)))
 
2097
        return null;
 
2098
    p = node_attr(n);
 
2099
    if (p == null)
 
2100
        return UNUSED_ATTRIBUTE;
 
2101
    if (attr_list_ref(p) == 0) {
 
2102
        fprintf(stdout,
 
2103
                "Node %d has an attribute list that is free already\n",
 
2104
                (int) n);
 
2105
        return UNUSED_ATTRIBUTE;
 
2106
    }
 
2107
    assert(vlink(p) != null);
 
2108
    while (vlink(p) != null) {
 
2109
        t = attribute_id(vlink(p));
 
2110
        if (t > i)
 
2111
            return UNUSED_ATTRIBUTE;
 
2112
        if (t == i) {
 
2113
            p = vlink(p);
 
2114
            break;
 
2115
        }
 
2116
        j++;
 
2117
        p = vlink(p);
 
2118
    }
 
2119
    if (attribute_id(p) != i)
 
2120
        return UNUSED_ATTRIBUTE;
 
2121
    /* if we are still here, the attribute exists */
 
2122
    p = node_attr(n);
 
2123
    if (attr_list_ref(p) > 1 || p == attr_list_cache) {
 
2124
        halfword q = copy_attribute_list(p);
 
2125
        if (attr_list_ref(p) > 1) {
 
2126
            delete_attribute_ref(node_attr(n));
 
2127
        }
 
2128
        attr_list_ref(q) = 1;
 
2129
        node_attr(n) = q;
 
2130
    }
 
2131
    p = vlink(node_attr(n));
 
2132
    while (j-- > 0)
 
2133
        p = vlink(p);
 
2134
    t = attribute_value(p);
 
2135
    if (val == UNUSED_ATTRIBUTE || t == val) {
 
2136
        attribute_value(p) = UNUSED_ATTRIBUTE;
 
2137
    }
 
2138
    return t;
 
2139
}
 
2140
 
 
2141
@ @c
 
2142
int has_attribute(halfword n, int i, int val)
 
2143
{
 
2144
    register halfword p;
 
2145
    if (!nodetype_has_attributes(type(n)))
 
2146
        return UNUSED_ATTRIBUTE;
 
2147
    p = node_attr(n);
 
2148
    if (p == null || vlink(p) == null)
 
2149
        return UNUSED_ATTRIBUTE;
 
2150
    p = vlink(p);
 
2151
    while (p != null) {
 
2152
        if (attribute_id(p) == i) {
 
2153
            int ret = attribute_value(p);
 
2154
            if (val == UNUSED_ATTRIBUTE || val == ret)
 
2155
                return ret;
 
2156
            return UNUSED_ATTRIBUTE;
 
2157
        } else if (attribute_id(p) > i) {
 
2158
            return UNUSED_ATTRIBUTE;
 
2159
        }
 
2160
        p = vlink(p);
 
2161
    }
 
2162
    return UNUSED_ATTRIBUTE;
 
2163
}
 
2164
 
 
2165
@ @c
 
2166
void print_short_node_contents(halfword p)
 
2167
{
 
2168
    switch (type(p)) {
 
2169
    case hlist_node:
 
2170
    case vlist_node:
 
2171
    case ins_node:
 
2172
    case whatsit_node:
 
2173
    case mark_node:
 
2174
    case adjust_node:
 
2175
    case unset_node:
 
2176
        print_char('[');
 
2177
        print_char(']');
 
2178
        break;
 
2179
    case rule_node:
 
2180
        print_char('|');
 
2181
        break;
 
2182
    case glue_node:
 
2183
        if (glue_ptr(p) != zero_glue)
 
2184
            print_char(' ');
 
2185
        break;
 
2186
    case math_node:
 
2187
        print_char('$');
 
2188
        break;
 
2189
    case disc_node:
 
2190
        short_display(vlink(pre_break(p)));
 
2191
        short_display(vlink(post_break(p)));
 
2192
        break;
 
2193
    default:
 
2194
        assert(1);
 
2195
        break;
 
2196
    }
 
2197
}
 
2198
 
 
2199
 
 
2200
@ @c
 
2201
static void show_pdftex_whatsit_rule_spec(int p)
 
2202
{
 
2203
    tprint("(");
 
2204
    print_rule_dimen(height(p));
 
2205
    print_char('+');
 
2206
    print_rule_dimen(depth(p));
 
2207
    tprint(")x");
 
2208
    print_rule_dimen(width(p));
 
2209
}
 
2210
 
 
2211
 
 
2212
 
 
2213
@ Each new type of node that appears in our data structure must be capable
 
2214
of being displayed, copied, destroyed, and so on. The routines that we
 
2215
need for write-oriented whatsits are somewhat like those for mark nodes;
 
2216
other extensions might, of course, involve more subtlety here.
 
2217
 
 
2218
@c
 
2219
static void print_write_whatsit(const char *s, pointer p)
 
2220
{
 
2221
    tprint_esc(s);
 
2222
    if (write_stream(p) < 16)
 
2223
        print_int(write_stream(p));
 
2224
    else if (write_stream(p) == 16)
 
2225
        print_char('*');
 
2226
    else
 
2227
        print_char('-');
 
2228
}
 
2229
 
 
2230
 
 
2231
@ @c
 
2232
static void show_whatsit_node(int p)
 
2233
{
 
2234
    switch (subtype(p)) {
 
2235
    case open_node:
 
2236
        print_write_whatsit("openout", p);
 
2237
        print_char('=');
 
2238
        print_file_name(open_name(p), open_area(p), open_ext(p));
 
2239
        break;
 
2240
    case write_node:
 
2241
        print_write_whatsit("write", p);
 
2242
        print_mark(write_tokens(p));
 
2243
        break;
 
2244
    case close_node:
 
2245
        print_write_whatsit("closeout", p);
 
2246
        break;
 
2247
    case special_node:
 
2248
        tprint_esc("special");
 
2249
        print_mark(write_tokens(p));
 
2250
        break;
 
2251
    case dir_node:
 
2252
        if (dir_dir(p) < 0) {
 
2253
            tprint_esc("enddir");
 
2254
            print_char(' ');
 
2255
            print_dir(dir_dir(p) + 64);
 
2256
        } else {
 
2257
            tprint_esc("begindir");
 
2258
            print_char(' ');
 
2259
            print_dir(dir_dir(p));
 
2260
        }
 
2261
        break;
 
2262
    case local_par_node:
 
2263
        tprint_esc("whatsit");
 
2264
        append_char('.');
 
2265
        print_ln();
 
2266
        print_current_string();
 
2267
        tprint_esc("localinterlinepenalty");
 
2268
        print_char('=');
 
2269
        print_int(local_pen_inter(p));
 
2270
        print_ln();
 
2271
        print_current_string();
 
2272
        tprint_esc("localbrokenpenalty");
 
2273
        print_char('=');
 
2274
        print_int(local_pen_broken(p));
 
2275
        print_ln();
 
2276
        print_current_string();
 
2277
        tprint_esc("localleftbox");
 
2278
        if (local_box_left(p) == null) {
 
2279
            tprint("=null");
 
2280
        } else {
 
2281
            append_char('.');
 
2282
            show_node_list(local_box_left(p));
 
2283
            decr(cur_length);
 
2284
        }
 
2285
        print_ln();
 
2286
        print_current_string();
 
2287
        tprint_esc("localrightbox");
 
2288
        if (local_box_right(p) == null) {
 
2289
            tprint("=null");
 
2290
        } else {
 
2291
            append_char('.');
 
2292
            show_node_list(local_box_right(p));
 
2293
            decr(cur_length);
 
2294
        }
 
2295
        decr(cur_length);
 
2296
        break;
 
2297
    case pdf_literal_node:
 
2298
        show_pdf_literal(p);
 
2299
        break;
 
2300
    case pdf_colorstack_node:
 
2301
        tprint_esc("pdfcolorstack ");
 
2302
        print_int(pdf_colorstack_stack(p));
 
2303
        switch (pdf_colorstack_cmd(p)) {
 
2304
        case colorstack_set:
 
2305
            tprint(" set ");
 
2306
            break;
 
2307
        case colorstack_push:
 
2308
            tprint(" push ");
 
2309
            break;
 
2310
        case colorstack_pop:
 
2311
            tprint(" pop");
 
2312
            break;
 
2313
        case colorstack_current:
 
2314
            tprint(" current");
 
2315
            break;
 
2316
        default:
 
2317
            confusion("pdfcolorstack");
 
2318
            break;
 
2319
        }
 
2320
        if (pdf_colorstack_cmd(p) <= colorstack_data)
 
2321
            print_mark(pdf_colorstack_data(p));
 
2322
        break;
 
2323
    case pdf_setmatrix_node:
 
2324
        tprint_esc("pdfsetmatrix");
 
2325
        print_mark(pdf_setmatrix_data(p));
 
2326
        break;
 
2327
    case pdf_save_node:
 
2328
        tprint_esc("pdfsave");
 
2329
        break;
 
2330
    case pdf_restore_node:
 
2331
        tprint_esc("pdfrestore");
 
2332
        break;
 
2333
    case cancel_boundary_node:
 
2334
        tprint_esc("noboundary");
 
2335
        break;
 
2336
    case late_lua_node:
 
2337
        tprint_esc("latelua");
 
2338
        print_int(late_lua_reg(p));
 
2339
        print_mark(late_lua_data(p));
 
2340
        break;
 
2341
    case close_lua_node:
 
2342
        tprint_esc("closelua");
 
2343
        print_int(late_lua_reg(p));
 
2344
        break;
 
2345
    case pdf_refobj_node:
 
2346
        tprint_esc("pdfrefobj");
 
2347
        if (obj_obj_is_stream(static_pdf, pdf_obj_objnum(p))) {
 
2348
            if (obj_obj_stream_attr(static_pdf, pdf_obj_objnum(p)) != LUA_NOREF) {
 
2349
                tprint(" attr");
 
2350
                lua_rawgeti(Luas, LUA_REGISTRYINDEX,
 
2351
                            obj_obj_stream_attr(static_pdf, pdf_obj_objnum(p)));
 
2352
                print_char(' ');
 
2353
                tprint((const char *) lua_tostring(Luas, -1));
 
2354
                lua_pop(Luas, 1);
 
2355
            }
 
2356
            tprint(" stream");
 
2357
        }
 
2358
        if (obj_obj_is_file(static_pdf, pdf_obj_objnum(p)))
 
2359
            tprint(" file");
 
2360
        if (obj_obj_data(static_pdf, pdf_obj_objnum(p)) != LUA_NOREF) {
 
2361
            lua_rawgeti(Luas, LUA_REGISTRYINDEX,
 
2362
                        obj_obj_data(static_pdf, pdf_obj_objnum(p)));
 
2363
            print_char(' ');
 
2364
            tprint((const char *) lua_tostring(Luas, -1));
 
2365
            lua_pop(Luas, 1);
 
2366
        }
 
2367
        break;
 
2368
    case pdf_refxform_node:
 
2369
    case pdf_refximage_node:
 
2370
        if (subtype(p) == pdf_refxform_node)
 
2371
            tprint_esc("pdfrefxform");
 
2372
        else
 
2373
            tprint_esc("pdfrefximage");
 
2374
        tprint("(");
 
2375
        print_scaled(height(p));
 
2376
        print_char('+');
 
2377
        print_scaled(depth(p));
 
2378
        tprint(")x");
 
2379
        print_scaled(width(p));
 
2380
        break;
 
2381
    case pdf_annot_node:
 
2382
        tprint_esc("pdfannot");
 
2383
        show_pdftex_whatsit_rule_spec(p);
 
2384
        print_mark(pdf_annot_data(p));
 
2385
        break;
 
2386
    case pdf_start_link_node:
 
2387
        tprint_esc("pdfstartlink");
 
2388
        show_pdftex_whatsit_rule_spec(p);
 
2389
        if (pdf_link_attr(p) != null) {
 
2390
            tprint(" attr");
 
2391
            print_mark(pdf_link_attr(p));
 
2392
        }
 
2393
        tprint(" action");
 
2394
        if (pdf_action_type(pdf_link_action(p)) == pdf_action_user) {
 
2395
            tprint(" user");
 
2396
            print_mark(pdf_action_tokens(pdf_link_action(p)));
 
2397
            return;
 
2398
        }
 
2399
        if (pdf_action_file(pdf_link_action(p)) != null) {
 
2400
            tprint(" file");
 
2401
            print_mark(pdf_action_file(pdf_link_action(p)));
 
2402
        }
 
2403
        switch (pdf_action_type(pdf_link_action(p))) {
 
2404
        case pdf_action_goto:
 
2405
            if (pdf_action_named_id(pdf_link_action(p)) > 0) {
 
2406
                tprint(" goto name");
 
2407
                print_mark(pdf_action_id(pdf_link_action(p)));
 
2408
            } else {
 
2409
                tprint(" goto num");
 
2410
                print_int(pdf_action_id(pdf_link_action(p)));
 
2411
            }
 
2412
            break;
 
2413
        case pdf_action_page:
 
2414
            tprint(" page");
 
2415
            print_int(pdf_action_id(pdf_link_action(p)));
 
2416
            print_mark(pdf_action_tokens(pdf_link_action(p)));
 
2417
            break;
 
2418
        case pdf_action_thread:
 
2419
            if (pdf_action_named_id(pdf_link_action(p)) > 0) {
 
2420
                tprint(" thread name");
 
2421
                print_mark(pdf_action_id(pdf_link_action(p)));
 
2422
            } else {
 
2423
                tprint(" thread num");
 
2424
                print_int(pdf_action_id(pdf_link_action(p)));
 
2425
            }
 
2426
            break;
 
2427
        default:
 
2428
            pdf_error("displaying", "unknown action type");
 
2429
            break;
 
2430
        }
 
2431
        break;
 
2432
    case pdf_end_link_node:
 
2433
        tprint_esc("pdfendlink");
 
2434
        break;
 
2435
    case pdf_dest_node:
 
2436
        tprint_esc("pdfdest");
 
2437
        if (pdf_dest_named_id(p) > 0) {
 
2438
            tprint(" name");
 
2439
            print_mark(pdf_dest_id(p));
 
2440
        } else {
 
2441
            tprint(" num");
 
2442
            print_int(pdf_dest_id(p));
 
2443
        }
 
2444
        print_char(' ');
 
2445
        switch (pdf_dest_type(p)) {
 
2446
        case pdf_dest_xyz:
 
2447
            tprint("xyz");
 
2448
            if (pdf_dest_xyz_zoom(p) != null) {
 
2449
                tprint(" zoom");
 
2450
                print_int(pdf_dest_xyz_zoom(p));
 
2451
            }
 
2452
            break;
 
2453
        case pdf_dest_fitbh:
 
2454
            tprint("fitbh");
 
2455
            break;
 
2456
        case pdf_dest_fitbv:
 
2457
            tprint("fitbv");
 
2458
            break;
 
2459
        case pdf_dest_fitb:
 
2460
            tprint("fitb");
 
2461
            break;
 
2462
        case pdf_dest_fith:
 
2463
            tprint("fith");
 
2464
            break;
 
2465
        case pdf_dest_fitv:
 
2466
            tprint("fitv");
 
2467
            break;
 
2468
        case pdf_dest_fitr:
 
2469
            tprint("fitr");
 
2470
            show_pdftex_whatsit_rule_spec(p);
 
2471
            break;
 
2472
        case pdf_dest_fit:
 
2473
            tprint("fit");
 
2474
            break;
 
2475
        default:
 
2476
            tprint("unknown!");
 
2477
            break;
 
2478
        }
 
2479
        break;
 
2480
    case pdf_thread_node:
 
2481
    case pdf_start_thread_node:
 
2482
        if (subtype(p) == pdf_thread_node)
 
2483
            tprint_esc("pdfthread");
 
2484
        else
 
2485
            tprint_esc("pdfstartthread");
 
2486
        tprint("(");
 
2487
        print_rule_dimen(height(p));
 
2488
        print_char('+');
 
2489
        print_rule_dimen(depth(p));
 
2490
        tprint(")x");
 
2491
        print_rule_dimen(width(p));
 
2492
        if (pdf_thread_attr(p) != null) {
 
2493
            tprint(" attr");
 
2494
            print_mark(pdf_thread_attr(p));
 
2495
        }
 
2496
        if (pdf_thread_named_id(p) > 0) {
 
2497
            tprint(" name");
 
2498
            print_mark(pdf_thread_id(p));
 
2499
        } else {
 
2500
            tprint(" num");
 
2501
            print_int(pdf_thread_id(p));
 
2502
        }
 
2503
        break;
 
2504
    case pdf_end_thread_node:
 
2505
        tprint_esc("pdfendthread");
 
2506
        break;
 
2507
    case pdf_save_pos_node:
 
2508
        tprint_esc("pdfsavepos");
 
2509
        break;
 
2510
    case user_defined_node:
 
2511
        tprint_esc("whatsit");
 
2512
        print_int(user_node_id(p));
 
2513
        print_char('=');
 
2514
        switch (user_node_type(p)) {
 
2515
        case 'a':
 
2516
            tprint("<>");
 
2517
            break;
 
2518
        case 'n':
 
2519
            tprint("[");
 
2520
            show_node_list(user_node_value(p));
 
2521
            tprint("]");
 
2522
            break;
 
2523
        case 's':
 
2524
            print_char('"');
 
2525
            print(user_node_value(p));
 
2526
            print_char('"');
 
2527
            break;
 
2528
        case 't':
 
2529
            print_mark(user_node_value(p));
 
2530
            break;
 
2531
        default:               /* only 'd' */
 
2532
            print_int(user_node_value(p));
 
2533
            break;
 
2534
        }
 
2535
        break;
 
2536
    default:
 
2537
        tprint("whatsit?");
 
2538
        break;
 
2539
    }
 
2540
}
 
2541
 
 
2542
 
 
2543
 
 
2544
@  Now we are ready for |show_node_list| itself. This procedure has been
 
2545
  written to be ``extra robust'' in the sense that it should not crash or get
 
2546
  into a loop even if the data structures have been messed up by bugs in
 
2547
  the rest of the program. You can safely call its parent routine
 
2548
  |show_box(p)| for arbitrary values of |p| when you are debugging \TeX.
 
2549
  However, in the presence of bad data, the procedure may
 
2550
  fetch a |memory_word| whose variant is different from the way it was stored;
 
2551
  for example, it might try to read |mem[p].hh| when |mem[p]|
 
2552
  contains a scaled integer, if |p| is a pointer that has been
 
2553
  clobbered or chosen at random.
 
2554
 
 
2555
 
 
2556
@ |str_room| need not be checked; see |show_box| 
 
2557
 
 
2558
@ Recursive calls on |show_node_list| therefore use the following pattern: 
 
2559
@c
 
2560
#define node_list_display(A) do {               \
 
2561
    append_char('.');                           \
 
2562
    show_node_list(A);                          \
 
2563
    flush_char();                               \
 
2564
} while (0)
 
2565
 
 
2566
void show_node_list(int p)
 
2567
{                               /* prints a node list symbolically */
 
2568
    int n;                      /* the number of items already printed at this level */
 
2569
    real g;                     /* a glue ratio, as a floating point number */
 
2570
    if ((int) cur_length > depth_threshold) {
 
2571
        if (p > null)
 
2572
            tprint(" []");      /* indicate that there's been some truncation */
 
2573
        return;
 
2574
    }
 
2575
    n = 0;
 
2576
    while (p != null) {
 
2577
        print_ln();
 
2578
        print_current_string(); /* display the nesting history */
 
2579
        if (int_par(tracing_online_code) < -2)
 
2580
            print_int(p);
 
2581
        incr(n);
 
2582
        if (n > breadth_max) {  /* time to stop */
 
2583
            tprint("etc.");
 
2584
            return;
 
2585
        }
 
2586
        /* Display node |p| */
 
2587
        if (is_char_node(p)) {
 
2588
            print_font_and_char(p);
 
2589
            if (is_ligature(p)) {
 
2590
                /* Display ligature |p|; */
 
2591
                tprint(" (ligature ");
 
2592
                if (is_leftboundary(p))
 
2593
                    print_char('|');
 
2594
                font_in_short_display = font(p);
 
2595
                short_display(lig_ptr(p));
 
2596
                if (is_rightboundary(p))
 
2597
                    print_char('|');
 
2598
                print_char(')');
 
2599
            }
 
2600
        } else {
 
2601
            switch (type(p)) {
 
2602
            case hlist_node:
 
2603
            case vlist_node:
 
2604
            case unset_node:
 
2605
                /* Display box |p|; */
 
2606
                if (type(p) == hlist_node)
 
2607
                    tprint_esc("h");
 
2608
                else if (type(p) == vlist_node)
 
2609
                    tprint_esc("v");
 
2610
                else
 
2611
                    tprint_esc("unset");
 
2612
                tprint("box(");
 
2613
                print_scaled(height(p));
 
2614
                print_char('+');
 
2615
                print_scaled(depth(p));
 
2616
                tprint(")x");
 
2617
                print_scaled(width(p));
 
2618
                if (type(p) == unset_node) {
 
2619
                    /* Display special fields of the unset node |p|; */
 
2620
                    if (span_count(p) != min_quarterword) {
 
2621
                        tprint(" (");
 
2622
                        print_int(span_count(p) + 1);
 
2623
                        tprint(" columns)");
 
2624
                    }
 
2625
                    if (glue_stretch(p) != 0) {
 
2626
                        tprint(", stretch ");
 
2627
                        print_glue(glue_stretch(p), glue_order(p), NULL);
 
2628
                    }
 
2629
                    if (glue_shrink(p) != 0) {
 
2630
                        tprint(", shrink ");
 
2631
                        print_glue(glue_shrink(p), glue_sign(p), NULL);
 
2632
                    }
 
2633
                } else {
 
2634
                    /* Display the value of |glue_set(p)| */
 
2635
                    /* The code will have to change in this place if |glue_ratio| is
 
2636
                       a structured type instead of an ordinary |real|. Note that this routine
 
2637
                       should avoid arithmetic errors even if the |glue_set| field holds an
 
2638
                       arbitrary random value. The following code assumes that a properly
 
2639
                       formed nonzero |real| number has absolute value $2^{20}$ or more when
 
2640
                       it is regarded as an integer; this precaution was adequate to prevent
 
2641
                       floating point underflow on the author's computer.
 
2642
                     */
 
2643
 
 
2644
                    g = (real) (glue_set(p));
 
2645
                    if ((g != 0.0) && (glue_sign(p) != normal)) {
 
2646
                        tprint(", glue set ");
 
2647
                        if (glue_sign(p) == shrinking)
 
2648
                            tprint("- ");
 
2649
                        if (g > 20000.0 || g < -20000.0) {
 
2650
                            if (g > 0.0)
 
2651
                                print_char('>');
 
2652
                            else
 
2653
                                tprint("< -");
 
2654
                            print_glue(20000 * unity, glue_order(p), NULL);
 
2655
                        } else {
 
2656
                            print_glue(round(unity * g), glue_order(p), NULL);
 
2657
                        }
 
2658
                    }
 
2659
 
 
2660
                    if (shift_amount(p) != 0) {
 
2661
                        tprint(", shifted ");
 
2662
                        print_scaled(shift_amount(p));
 
2663
                    }
 
2664
                    tprint(", direction ");
 
2665
                    print_dir(box_dir(p));
 
2666
                }
 
2667
                node_list_display(list_ptr(p)); /* recursive call */
 
2668
                break;
 
2669
            case rule_node:
 
2670
                /* Display rule |p|; */
 
2671
                tprint_esc("rule(");
 
2672
                print_rule_dimen(height(p));
 
2673
                print_char('+');
 
2674
                print_rule_dimen(depth(p));
 
2675
                tprint(")x");
 
2676
                print_rule_dimen(width(p));
 
2677
                break;
 
2678
            case ins_node:
 
2679
                /* Display insertion |p|; */
 
2680
                tprint_esc("insert");
 
2681
                print_int(subtype(p));
 
2682
                tprint(", natural size ");
 
2683
                print_scaled(height(p));
 
2684
                tprint("; split(");
 
2685
                print_spec(split_top_ptr(p), NULL);
 
2686
                print_char(',');
 
2687
                print_scaled(depth(p));
 
2688
                tprint("); float cost ");
 
2689
                print_int(float_cost(p));
 
2690
                node_list_display(ins_ptr(p));  /* recursive call */
 
2691
                break;
 
2692
            case whatsit_node:
 
2693
                show_whatsit_node(p);
 
2694
                break;
 
2695
            case glue_node:
 
2696
                /* Display glue |p|; */
 
2697
                if (subtype(p) >= a_leaders) {
 
2698
                    /* Display leaders |p|; */
 
2699
                    tprint_esc("");
 
2700
                    switch (subtype(p)) {
 
2701
                    case a_leaders:
 
2702
                        break;
 
2703
                    case c_leaders:
 
2704
                        print_char('c');
 
2705
                        break;
 
2706
                    case x_leaders:
 
2707
                        print_char('x');
 
2708
                        break;
 
2709
                    case g_leaders:
 
2710
                        print_char('g');
 
2711
                        break;
 
2712
                    default:
 
2713
                        assert(0);
 
2714
                    }
 
2715
                    tprint("leaders ");
 
2716
                    print_spec(glue_ptr(p), NULL);
 
2717
                    node_list_display(leader_ptr(p));   /* recursive call */
 
2718
                } else {
 
2719
                    tprint_esc("glue");
 
2720
                    if (subtype(p) != normal) {
 
2721
                        print_char('(');
 
2722
                        if ((subtype(p) - 1) < thin_mu_skip_code) {
 
2723
                            print_cmd_chr(assign_glue_cmd,
 
2724
                                          glue_base + (subtype(p) - 1));
 
2725
                        } else if (subtype(p) < cond_math_glue) {
 
2726
                            print_cmd_chr(assign_mu_glue_cmd,
 
2727
                                          glue_base + (subtype(p) - 1));
 
2728
                        } else if (subtype(p) == cond_math_glue) {
 
2729
                            tprint_esc("nonscript");
 
2730
                        } else {
 
2731
                            tprint_esc("mskip");
 
2732
                        }
 
2733
                        print_char(')');
 
2734
                    }
 
2735
                    if (subtype(p) != cond_math_glue) {
 
2736
                        print_char(' ');
 
2737
                        if (subtype(p) < cond_math_glue)
 
2738
                            print_spec(glue_ptr(p), NULL);
 
2739
                        else
 
2740
                            print_spec(glue_ptr(p), "mu");
 
2741
                    }
 
2742
                }
 
2743
                break;
 
2744
            case margin_kern_node:
 
2745
                tprint_esc("kern");
 
2746
                print_scaled(width(p));
 
2747
                if (subtype(p) == left_side)
 
2748
                    tprint(" (left margin)");
 
2749
                else
 
2750
                    tprint(" (right margin)");
 
2751
                break;
 
2752
            case kern_node:
 
2753
                /* Display kern |p|; */
 
2754
                /*  An ``explicit'' kern value is indicated implicitly by an explicit space. */
 
2755
                if (subtype(p) != mu_glue) {
 
2756
                    tprint_esc("kern");
 
2757
                    if (subtype(p) != normal)
 
2758
                        print_char(' ');
 
2759
                    print_scaled(width(p));
 
2760
                    if (subtype(p) == acc_kern)
 
2761
                        tprint(" (for accent)");
 
2762
                } else {
 
2763
                    tprint_esc("mkern");
 
2764
                    print_scaled(width(p));
 
2765
                    tprint("mu");
 
2766
                }
 
2767
                break;
 
2768
            case math_node:
 
2769
                /* Display math node |p|; */
 
2770
                tprint_esc("math");
 
2771
                if (subtype(p) == before)
 
2772
                    tprint("on");
 
2773
                else
 
2774
                    tprint("off");
 
2775
                if (width(p) != 0) {
 
2776
                    tprint(", surrounded ");
 
2777
                    print_scaled(width(p));
 
2778
                }
 
2779
                break;
 
2780
            case penalty_node:
 
2781
                /* Display penalty |p|; */
 
2782
                tprint_esc("penalty ");
 
2783
                print_int(penalty(p));
 
2784
                break;
 
2785
            case disc_node:
 
2786
                /* Display discretionary |p|; */
 
2787
                /* The |post_break| list of a discretionary node is indicated by a prefixed
 
2788
                   `\.{\char'174}' instead of the `\..' before the |pre_break| list. */
 
2789
                tprint_esc("discretionary");
 
2790
                if (vlink(no_break(p)) != null) {
 
2791
                    tprint(" replacing ");
 
2792
                    node_list_display(vlink(no_break(p)));
 
2793
                }
 
2794
                node_list_display(vlink(pre_break(p))); /* recursive call */
 
2795
                append_char('|');
 
2796
                show_node_list(vlink(post_break(p)));
 
2797
                flush_char();   /* recursive call */
 
2798
                break;
 
2799
            case mark_node:
 
2800
                /* Display mark |p|; */
 
2801
                tprint_esc("mark");
 
2802
                if (mark_class(p) != 0) {
 
2803
                    print_char('s');
 
2804
                    print_int(mark_class(p));
 
2805
                }
 
2806
                print_mark(mark_ptr(p));
 
2807
                break;
 
2808
            case adjust_node:
 
2809
                /* Display adjustment |p|; */
 
2810
                tprint_esc("vadjust");
 
2811
                if (adjust_pre(p) != 0)
 
2812
                    tprint(" pre ");
 
2813
                node_list_display(adjust_ptr(p));       /* recursive call */
 
2814
                break;
 
2815
            default:
 
2816
                show_math_node(p);
 
2817
                break;
 
2818
            }
 
2819
        }
 
2820
        p = vlink(p);
 
2821
    }
 
2822
}
 
2823
 
 
2824
@ This routine finds the 'base' width of a horizontal box, using the same logic
 
2825
  that \TeX82 used for \.{\\predisplaywidth} */
 
2826
 
 
2827
@c
 
2828
pointer actual_box_width(pointer r, scaled base_width)
 
2829
{
 
2830
    scaled w;                   /* calculated |size| */
 
2831
    pointer p;                  /* current node when calculating |pre_display_size| */
 
2832
    pointer q;                  /* glue specification when calculating |pre_display_size| */
 
2833
    internal_font_number f;     /* font in current |char_node| */
 
2834
    scaled d;                   /* increment to |v| */
 
2835
    scaled v;                   /* |w| plus possible glue amount */
 
2836
    w = -max_dimen;
 
2837
    v = shift_amount(r) + base_width;
 
2838
    p = list_ptr(r);
 
2839
    while (p != null) {
 
2840
        if (is_char_node(p)) {
 
2841
            f = font(p);
 
2842
            d = glyph_width(p);
 
2843
            goto found;
 
2844
        }
 
2845
        switch (type(p)) {
 
2846
        case hlist_node:
 
2847
        case vlist_node:
 
2848
        case rule_node:
 
2849
            d = width(p);
 
2850
            goto found;
 
2851
            break;
 
2852
        case margin_kern_node:
 
2853
            d = width(p);
 
2854
            break;
 
2855
        case kern_node:
 
2856
            d = width(p);
 
2857
            break;
 
2858
        case math_node:
 
2859
            d = surround(p);
 
2860
            break;
 
2861
        case glue_node:
 
2862
            /* We need to be careful that |w|, |v|, and |d| do not depend on any |glue_set|
 
2863
               values, since such values are subject to system-dependent rounding.
 
2864
               System-dependent numbers are not allowed to infiltrate parameters like
 
2865
               |pre_display_size|, since \TeX82 is supposed to make the same decisions on all
 
2866
               machines.
 
2867
             */
 
2868
            q = glue_ptr(p);
 
2869
            d = width(q);
 
2870
            if (glue_sign(r) == stretching) {
 
2871
                if ((glue_order(r) == stretch_order(q))
 
2872
                    && (stretch(q) != 0))
 
2873
                    v = max_dimen;
 
2874
            } else if (glue_sign(r) == shrinking) {
 
2875
                if ((glue_order(r) == shrink_order(q))
 
2876
                    && (shrink(q) != 0))
 
2877
                    v = max_dimen;
 
2878
            }
 
2879
            if (subtype(p) >= a_leaders)
 
2880
                goto found;
 
2881
            break;
 
2882
        case whatsit_node:
 
2883
            if ((subtype(p) == pdf_refxform_node)
 
2884
                || (subtype(p) == pdf_refximage_node))
 
2885
                d = width(p);
 
2886
            else
 
2887
                d = 0;
 
2888
            break;
 
2889
        default:
 
2890
            d = 0;
 
2891
            break;
 
2892
        }
 
2893
        if (v < max_dimen)
 
2894
            v = v + d;
 
2895
        goto not_found;
 
2896
      found:
 
2897
        if (v < max_dimen) {
 
2898
            v = v + d;
 
2899
            w = v;
 
2900
        } else {
 
2901
            w = max_dimen;
 
2902
            break;
 
2903
        }
 
2904
      not_found:
 
2905
        p = vlink(p);
 
2906
    }
 
2907
    return w;
 
2908
}
 
2909
 
 
2910
 
 
2911
@ @c
 
2912
halfword tail_of_list(halfword p)
 
2913
{
 
2914
    halfword q = p;
 
2915
    while (vlink(q) != null)
 
2916
        q = vlink(q);
 
2917
    return q;
 
2918
}
 
2919
 
 
2920
 
 
2921
@ |delete_glue_ref| is called when a pointer to a glue
 
2922
   specification is being withdrawn.
 
2923
 
 
2924
@c
 
2925
#define fast_delete_glue_ref(A) do {            \
 
2926
    if (glue_ref_count(A)==null) {              \
 
2927
      flush_node(A);                            \
 
2928
    } else {                                    \
 
2929
      decr(glue_ref_count(A));                  \
 
2930
    }                                           \
 
2931
  } while (0)
 
2932
 
 
2933
void delete_glue_ref(halfword p)
 
2934
{                               /* |p| points to a glue specification */
 
2935
    assert(type(p) == glue_spec_node);
 
2936
    fast_delete_glue_ref(p);
 
2937
}
 
2938
 
 
2939
@ @c
 
2940
int var_used;
 
2941
halfword temp_ptr;              /* a pointer variable for occasional emergency use */
 
2942
 
 
2943
 
 
2944
@ Attribute lists need two extra globals to increase processing efficiency.
 
2945
|max_used_attr| limits the test loop that checks for set attributes, and
 
2946
|attr_list_cache| contains a pointer to an already created attribute list.  It is
 
2947
set to the special value |cache_disabled| when the current value can no longer be
 
2948
trusted: after an assignment to an attribute register, and after a group has
 
2949
ended.
 
2950
 
 
2951
@c
 
2952
int max_used_attr;              /* maximum assigned attribute id  */
 
2953
halfword attr_list_cache;
 
2954
 
 
2955
@ From the computer's standpoint, \TeX's chief mission is to create
 
2956
horizontal and vertical lists. We shall now investigate how the elements
 
2957
of these lists are represented internally as nodes in the dynamic memory.
 
2958
 
 
2959
A horizontal or vertical list is linked together by |link| fields in
 
2960
the first word of each node. Individual nodes represent boxes, glue,
 
2961
penalties, or special things like discretionary hyphens; because of this
 
2962
variety, some nodes are longer than others, and we must distinguish different
 
2963
kinds of nodes. We do this by putting a `|type|' field in the first word,
 
2964
together with the link and an optional `|subtype|'.
 
2965
 
 
2966
 
 
2967
@ Character nodes appear only in horizontal lists, never in vertical lists.
 
2968
 
 
2969
An |hlist_node| stands for a box that was made from a horizontal list.
 
2970
Each |hlist_node| is seven words long, and contains the following fields
 
2971
(in addition to the mandatory |type| and |link|, which we shall not
 
2972
mention explicitly when discussing the other node types): The |height| and
 
2973
|width| and |depth| are scaled integers denoting the dimensions of the
 
2974
box.  There is also a |shift_amount| field, a scaled integer indicating
 
2975
how much this box should be lowered (if it appears in a horizontal list),
 
2976
or how much it should be moved to the right (if it appears in a vertical
 
2977
list). There is a |list_ptr| field, which points to the beginning of the
 
2978
list from which this box was fabricated; if |list_ptr| is |null|, the box
 
2979
is empty. Finally, there are three fields that represent the setting of
 
2980
the glue:  |glue_set(p)| is a word of type |glue_ratio| that represents
 
2981
the proportionality constant for glue setting; |glue_sign(p)| is
 
2982
|stretching| or |shrinking| or |normal| depending on whether or not the
 
2983
glue should stretch or shrink or remain rigid; and |glue_order(p)|
 
2984
specifies the order of infinity to which glue setting applies (|normal|,
 
2985
|sfi|, |fil|, |fill|, or |filll|). The |subtype| field is not used.
 
2986
 
 
2987
@ The |new_null_box| function returns a pointer to an |hlist_node| in
 
2988
which all subfields have the values corresponding to `\.{\\hbox\{\}}'.
 
2989
The |subtype| field is set to |min_quarterword|, since that's the desired
 
2990
|span_count| value if this |hlist_node| is changed to an |unset_node|.
 
2991
 
 
2992
@c
 
2993
halfword new_null_box(void)
 
2994
{                               /* creates a new box node */
 
2995
    halfword p;                 /* the new node */
 
2996
    p = new_node(hlist_node, min_quarterword);
 
2997
    box_dir(p) = text_direction;
 
2998
    return p;
 
2999
}
 
3000
 
 
3001
 
 
3002
@ A |vlist_node| is like an |hlist_node| in all respects except that it
 
3003
contains a vertical list.
 
3004
 
 
3005
 
 
3006
@ A |rule_node| stands for a solid black rectangle; it has |width|,
 
3007
|depth|, and |height| fields just as in an |hlist_node|. However, if
 
3008
any of these dimensions is $-2^{30}$, the actual value will be determined
 
3009
by running the rule up to the boundary of the innermost enclosing box.
 
3010
This is called a ``running dimension.'' The |width| is never running in
 
3011
an hlist; the |height| and |depth| are never running in a~vlist.
 
3012
 
 
3013
@ A new rule node is delivered by the |new_rule| function. It
 
3014
makes all the dimensions ``running,'' so you have to change the
 
3015
ones that are not allowed to run.
 
3016
 
 
3017
@c
 
3018
halfword new_rule(void)
 
3019
{
 
3020
    halfword p;                 /* the new node */
 
3021
    p = new_node(rule_node, 0); /* the |subtype| is not used */
 
3022
    return p;
 
3023
}
 
3024
 
 
3025
 
 
3026
@ Insertions are represented by |ins_node| records, where the |subtype|
 
3027
indicates the corresponding box number. For example, `\.{\\insert 250}'
 
3028
leads to an |ins_node| whose |subtype| is |250+min_quarterword|.
 
3029
The |height| field of an |ins_node| is slightly misnamed; it actually holds
 
3030
the natural height plus depth of the vertical list being inserted.
 
3031
The |depth| field holds the |split_max_depth| to be used in case this
 
3032
insertion is split, and the |split_top_ptr| points to the corresponding
 
3033
|split_top_skip|. The |float_cost| field holds the |floating_penalty| that
 
3034
will be used if this insertion floats to a subsequent page after a
 
3035
split insertion of the same class.  There is one more field, the
 
3036
|ins_ptr|, which points to the beginning of the vlist for the insertion.
 
3037
 
 
3038
@ A |mark_node| has a |mark_ptr| field that points to the reference count
 
3039
of a token list that contains the user's \.{\\mark} text.
 
3040
In addition there is a |mark_class| field that contains the mark class.
 
3041
 
 
3042
@ An |adjust_node|, which occurs only in horizontal lists,
 
3043
specifies material that will be moved out into the surrounding
 
3044
vertical list; i.e., it is used to implement \TeX's `\.{\\vadjust}'
 
3045
operation.  The |adjust_ptr| field points to the vlist containing this
 
3046
material.
 
3047
 
 
3048
@ A |glyph_node|, which occurs only in horizontal lists, specifies a
 
3049
glyph in a particular font, along with its attribute list. Older
 
3050
versions of \TeX\ could use token memory for characters, because the
 
3051
font,char combination would fit in a single word (both values were
 
3052
required to be strictly less than $2^{16}$). In LuaTeX, room is
 
3053
needed for characters that are larger than that, as well as a pointer
 
3054
to a potential attribute list, and the two displacement values.
 
3055
 
 
3056
In turn, that made the node so large that it made sense to merge
 
3057
ligature glyphs as well, as that requires only one extra pointer.  A
 
3058
few extra classes of glyph nodes will be introduced later.  The
 
3059
unification of all those types makes it easier to manipulate lists of
 
3060
glyphs. The subtype differentiates various glyph kinds.
 
3061
 
 
3062
First, here is a function that returns a pointer to a glyph node for a given
 
3063
glyph in a given font. If that glyph doesn't exist, |null| is returned
 
3064
instead.  Nodes of this subtype are directly created only for accents
 
3065
and their base (through |make_accent|), and math nucleus items (in the
 
3066
conversion from |mlist| to |hlist|).
 
3067
 
 
3068
@c
 
3069
halfword new_glyph(int f, int c)
 
3070
{
 
3071
    halfword p = null;          /* the new node */
 
3072
    if ((f == 0) || (char_exists(f, c))) {
 
3073
        p = new_glyph_node();
 
3074
        set_to_glyph(p);
 
3075
        font(p) = f;
 
3076
        character(p) = c;
 
3077
    }
 
3078
    return p;
 
3079
}
 
3080
 
 
3081
 
 
3082
@ A subset of the glyphs nodes represent ligatures: characters
 
3083
fabricated from the interaction of two or more actual characters.  The
 
3084
characters that generated the ligature have not been forgotten, since
 
3085
they are needed for diagnostic messages; the |lig_ptr| field points to
 
3086
a linked list of character nodes for all original characters that have
 
3087
been deleted. (This list might be empty if the characters that
 
3088
generated the ligature were retained in other nodes.)
 
3089
 
 
3090
The |subtype| field of these |glyph_node|s is 1, plus 2 and/or 1 if
 
3091
the original source of the ligature included implicit left and/or
 
3092
right boundaries. These nodes are created by the C function |new_ligkern|.
 
3093
 
 
3094
A third general type of glyphs could be called a character, as it
 
3095
only appears in lists that are not yet processed by the ligaturing and
 
3096
kerning steps of the program.
 
3097
 
 
3098
|main_control| inserts these, and they are later converted to
 
3099
|subtype_normal| by |new_ligkern|.
 
3100
 
 
3101
@c
 
3102
quarterword norm_min(int h)
 
3103
{
 
3104
    if (h <= 0)
 
3105
        return 1;
 
3106
    else if (h >= 255)
 
3107
        return 255;
 
3108
    else
 
3109
        return (quarterword) h;
 
3110
}
 
3111
 
 
3112
halfword new_char(int f, int c)
 
3113
{
 
3114
    halfword p;                 /* the new node */
 
3115
    p = new_glyph_node();
 
3116
    set_to_character(p);
 
3117
    font(p) = f;
 
3118
    character(p) = c;
 
3119
    lang_data(p) =
 
3120
        make_lang_data(uc_hyph, cur_lang, left_hyphen_min, right_hyphen_min);
 
3121
    return p;
 
3122
}
 
3123
 
 
3124
 
 
3125
@ Left and right ghost glyph nodes are the result of \.{\\leftghost}
 
3126
and \.{\\rightghost}, respectively. They are going to be removed by
 
3127
|new_ligkern|, at the end of which they are no longer needed.
 
3128
 
 
3129
@ Here are a few handy helpers used by the list output routines.
 
3130
 
 
3131
@c
 
3132
scaled glyph_width(halfword p)
 
3133
{
 
3134
    scaled w;
 
3135
    w = char_width(font(p), character(p));
 
3136
    return w;
 
3137
}
 
3138
 
 
3139
scaled glyph_height(halfword p)
 
3140
{
 
3141
    scaled w;
 
3142
    w = char_height(font(p), character(p)) + y_displace(p);
 
3143
    if (w < 0)
 
3144
        w = 0;
 
3145
    return w;
 
3146
}
 
3147
 
 
3148
scaled glyph_depth(halfword p)
 
3149
{
 
3150
    scaled w;
 
3151
    w = char_depth(font(p), character(p));
 
3152
    if (y_displace(p) > 0)
 
3153
        w = w - y_displace(p);
 
3154
    if (w < 0)
 
3155
        w = 0;
 
3156
    return w;
 
3157
}
 
3158
 
 
3159
 
 
3160
@ A |disc_node|, which occurs only in horizontal lists, specifies a
 
3161
``dis\-cretion\-ary'' line break. If such a break occurs at node |p|, the text
 
3162
that starts at |pre_break(p)| will precede the break, the text that starts at
 
3163
|post_break(p)| will follow the break, and text that appears in
 
3164
|no_break(p)| nodes will be ignored. For example, an ordinary
 
3165
discretionary hyphen, indicated by `\.{\\-}', yields a |disc_node| with
 
3166
|pre_break| pointing to a |char_node| containing a hyphen, |post_break=null|,
 
3167
and |no_break=null|.
 
3168
 
 
3169
{TODO: Knuth said: All three of the discretionary texts must be lists
 
3170
that consist entirely of character, kern, box and rule nodes.}
 
3171
 
 
3172
If |subtype(p)=automatic_disc|, the |ex_hyphen_penalty| will be charged for this
 
3173
break.  Otherwise the |hyphen_penalty| will be charged.  The texts will
 
3174
actually be substituted into the list by the line-breaking algorithm if it
 
3175
decides to make the break, and the discretionary node will disappear at
 
3176
that time; thus, the output routine sees only discretionaries that were
 
3177
not chosen.
 
3178
 
 
3179
@c
 
3180
halfword new_disc(void)
 
3181
{                               /* creates an empty |disc_node| */
 
3182
    halfword p;                 /* the new node */
 
3183
    p = new_node(disc_node, 0);
 
3184
    return p;
 
3185
}
 
3186
 
 
3187
@ A |whatsit_node| is a wild card reserved for extensions to \TeX. The
 
3188
|subtype| field in its first word says what `\\{whatsit}' it is, and
 
3189
implicitly determines the node size (which must be 2 or more) and the
 
3190
format of the remaining words. When a |whatsit_node| is encountered
 
3191
in a list, special actions are invoked; knowledgeable people who are
 
3192
careful not to mess up the rest of \TeX\ are able to make \TeX\ do new
 
3193
things by adding code at the end of the program. For example, there
 
3194
might be a `\TeX nicolor' extension to specify different colors of ink,
 
3195
@^extensions to \TeX@>
 
3196
and the whatsit node might contain the desired parameters.
 
3197
 
 
3198
The present implementation of \TeX\ treats the features associated with
 
3199
`\.{\\write}' and `\.{\\special}' as if they were extensions, in order to
 
3200
illustrate how such routines might be coded. We shall defer further
 
3201
discussion of extensions until the end of this program.
 
3202
 
 
3203
@ A |math_node|, which occurs only in horizontal lists, appears before and
 
3204
after mathematical formulas. The |subtype| field is |before| before the
 
3205
formula and |after| after it. There is a |surround| field, which represents
 
3206
the amount of surrounding space inserted by \.{\\mathsurround}.
 
3207
 
 
3208
@c
 
3209
halfword new_math(scaled w, int s)
 
3210
{
 
3211
    halfword p;                 /* the new node */
 
3212
    p = new_node(math_node, s);
 
3213
    surround(p) = w;
 
3214
    return p;
 
3215
}
 
3216
 
 
3217
@ \TeX\ makes use of the fact that |hlist_node|, |vlist_node|,
 
3218
|rule_node|, |ins_node|, |mark_node|, |adjust_node|,
 
3219
|disc_node|, |whatsit_node|, and |math_node| are at the low end of the
 
3220
type codes, by permitting a break at glue in a list if and only if the
 
3221
|type| of the previous node is less than |math_node|. Furthermore, a
 
3222
node is discarded after a break if its type is |math_node| or~more.
 
3223
 
 
3224
@ A |glue_node| represents glue in a list. However, it is really only
 
3225
a pointer to a separate glue specification, since \TeX\ makes use of the
 
3226
fact that many essentially identical nodes of glue are usually present.
 
3227
If |p| points to a |glue_node|, |glue_ptr(p)| points to
 
3228
another packet of words that specify the stretch and shrink components, etc.
 
3229
 
 
3230
Glue nodes also serve to represent leaders; the |subtype| is used to
 
3231
distinguish between ordinary glue (which is called |normal|) and the three
 
3232
kinds of leaders (which are called |a_leaders|, |c_leaders|, and |x_leaders|).
 
3233
The |leader_ptr| field points to a rule node or to a box node containing the
 
3234
leaders; it is set to |null| in ordinary glue nodes.
 
3235
 
 
3236
Many kinds of glue are computed from \TeX's ``skip'' parameters, and
 
3237
it is helpful to know which parameter has led to a particular glue node.
 
3238
Therefore the |subtype| is set to indicate the source of glue, whenever
 
3239
it originated as a parameter. We will be defining symbolic names for the
 
3240
parameter numbers later (e.g., |line_skip_code=0|, |baseline_skip_code=1|,
 
3241
etc.); it suffices for now to say that the |subtype| of parametric glue
 
3242
will be the same as the parameter number, plus~one.
 
3243
 
 
3244
@ In math formulas there are two more possibilities for the |subtype| in a
 
3245
glue node: |mu_glue| denotes an \.{\\mskip} (where the units are scaled \.{mu}
 
3246
instead of scaled \.{pt}); and |cond_math_glue| denotes the `\.{\\nonscript}'
 
3247
feature that cancels the glue node immediately following if it appears
 
3248
in a subscript.
 
3249
 
 
3250
@ A glue specification has a halfword reference count in its first word,
 
3251
@^reference counts@>
 
3252
representing |null| plus the number of glue nodes that point to it (less one).
 
3253
Note that the reference count appears in the same position as
 
3254
the |link| field in list nodes; this is the field that is initialized
 
3255
to |null| when a node is allocated, and it is also the field that is flagged
 
3256
by |empty_flag| in empty nodes.
 
3257
 
 
3258
Glue specifications also contain three |scaled| fields, for the |width|,
 
3259
|stretch|, and |shrink| dimensions. Finally, there are two one-byte
 
3260
fields called |stretch_order| and |shrink_order|; these contain the
 
3261
orders of infinity (|normal|, |sfi|, |fil|, |fill|, or |filll|)
 
3262
corresponding to the stretch and shrink values.
 
3263
 
 
3264
@ Here is a function that returns a pointer to a copy of a glue spec.
 
3265
The reference count in the copy is |null|, because there is assumed
 
3266
to be exactly one reference to the new specification.
 
3267
 
 
3268
@c
 
3269
halfword new_spec(halfword p)
 
3270
{                               /* duplicates a glue specification */
 
3271
    halfword q;                 /* the new spec */
 
3272
    q = copy_node(p);
 
3273
    glue_ref_count(q) = null;
 
3274
    return q;
 
3275
}
 
3276
 
 
3277
@ And here's a function that creates a glue node for a given parameter
 
3278
identified by its code number; for example,
 
3279
|new_param_glue(line_skip_code)| returns a pointer to a glue node for the
 
3280
current \.{\\lineskip}.
 
3281
 
 
3282
@c
 
3283
halfword new_param_glue(int n)
 
3284
{
 
3285
    halfword p;                 /* the new node */
 
3286
    halfword q;                 /* the glue specification */
 
3287
    p = new_node(glue_node, n + 1);
 
3288
    q = glue_par(n);
 
3289
    glue_ptr(p) = q;
 
3290
    incr(glue_ref_count(q));
 
3291
    return p;
 
3292
}
 
3293
 
 
3294
@ Glue nodes that are more or less anonymous are created by |new_glue|,
 
3295
whose argument points to a glue specification.
 
3296
 
 
3297
@c
 
3298
halfword new_glue(halfword q)
 
3299
{
 
3300
    halfword p;                 /* the new node */
 
3301
    p = new_node(glue_node, normal);
 
3302
    glue_ptr(p) = q;
 
3303
    incr(glue_ref_count(q));
 
3304
    return p;
 
3305
}
 
3306
 
 
3307
@ Still another subroutine is needed: This one is sort of a combination
 
3308
of |new_param_glue| and |new_glue|. It creates a glue node for one of
 
3309
the current glue parameters, but it makes a fresh copy of the glue
 
3310
specification, since that specification will probably be subject to change,
 
3311
while the parameter will stay put. The global variable |temp_ptr| is
 
3312
set to the address of the new spec.
 
3313
 
 
3314
@c
 
3315
halfword new_skip_param(int n)
 
3316
{
 
3317
    halfword p;                 /* the new node */
 
3318
    temp_ptr = new_spec(glue_par(n));
 
3319
    p = new_glue(temp_ptr);
 
3320
    glue_ref_count(temp_ptr) = null;
 
3321
    subtype(p) = (quarterword) (n + 1);
 
3322
    return p;
 
3323
}
 
3324
 
 
3325
@ A |kern_node| has a |width| field to specify a (normally negative)
 
3326
amount of spacing. This spacing correction appears in horizontal lists
 
3327
between letters like A and V when the font designer said that it looks
 
3328
better to move them closer together or further apart. A kern node can
 
3329
also appear in a vertical list, when its `|width|' denotes additional
 
3330
spacing in the vertical direction. The |subtype| is either |normal| (for
 
3331
kerns inserted from font information or math mode calculations) or |explicit|
 
3332
(for kerns inserted from \.{\\kern} and \.{\\/} commands) or |acc_kern|
 
3333
(for kerns inserted from non-math accents) or |mu_glue| (for kerns
 
3334
inserted from \.{\\mkern} specifications in math formulas).
 
3335
 
 
3336
@ The |new_kern| function creates a kern node having a given width.
 
3337
 
 
3338
@c
 
3339
halfword new_kern(scaled w)
 
3340
{
 
3341
    halfword p;                 /* the new node */
 
3342
    p = new_node(kern_node, normal);
 
3343
    width(p) = w;
 
3344
    return p;
 
3345
}
 
3346
 
 
3347
@ A |penalty_node| specifies the penalty associated with line or page
 
3348
breaking, in its |penalty| field. This field is a fullword integer, but
 
3349
the full range of integer values is not used: Any penalty |>=10000| is
 
3350
treated as infinity, and no break will be allowed for such high values.
 
3351
Similarly, any penalty |<=-10000| is treated as negative infinity, and a
 
3352
break will be forced.
 
3353
 
 
3354
@ Anyone who has been reading the last few sections of the program will
 
3355
be able to guess what comes next.
 
3356
 
 
3357
@c
 
3358
halfword new_penalty(int m)
 
3359
{
 
3360
    halfword p;                 /* the new node */
 
3361
    p = new_node(penalty_node, 0);      /* the |subtype| is not used */
 
3362
    penalty(p) = m;
 
3363
    return p;
 
3364
}
 
3365
 
 
3366
@ You might think that we have introduced enough node types by now. Well,
 
3367
almost, but there is one more: An |unset_node| has nearly the same format
 
3368
as an |hlist_node| or |vlist_node|; it is used for entries in \.{\\halign}
 
3369
or \.{\\valign} that are not yet in their final form, since the box
 
3370
dimensions are their ``natural'' sizes before any glue adjustment has been
 
3371
made. The |glue_set| word is not present; instead, we have a |glue_stretch|
 
3372
field, which contains the total stretch of order |glue_order| that is
 
3373
present in the hlist or vlist being boxed.
 
3374
Similarly, the |shift_amount| field is replaced by a |glue_shrink| field,
 
3375
containing the total shrink of order |glue_sign| that is present.
 
3376
The |subtype| field is called |span_count|; an unset box typically
 
3377
contains the data for |qo(span_count)+1| columns.
 
3378
Unset nodes will be changed to box nodes when alignment is completed.
 
3379
 
 
3380
In fact, there are still more types coming. When we get to math formula
 
3381
processing we will see that a |style_node| has |type=14|; and a number
 
3382
of larger type codes will also be defined, for use in math mode only.
 
3383
 
 
3384
Warning: If any changes are made to these data structure layouts, such as
 
3385
changing any of the node sizes or even reordering the words of nodes,
 
3386
the |copy_node_list| procedure and the memory initialization code
 
3387
below may have to be changed. Such potentially dangerous parts of the
 
3388
program are listed in the index under `data structure assumptions'.
 
3389
@!@^data structure assumptions@>
 
3390
However, other references to the nodes are made symbolically in terms of
 
3391
the \.{WEB} macro definitions above, so that format changes will leave
 
3392
\TeX's other algorithms intact.
 
3393
@^system dependencies@>