3
% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org>
5
% This file is part of LuaTeX.
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.
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.
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/>.
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 $";
26
#include "lua/luatex-api.h"
32
#define DEBUG_OUT stdout
34
#define adjust_pre subtype
35
#define attribute(A) eqtb[attribute_base+(A)].cint
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)
42
#define text_direction int_par(text_direction_code)
44
#define MAX_CHAIN_SIZE 13
46
memory_word *volatile varmem = NULL;
49
char *varmem_sizes = NULL;
52
halfword var_mem_max = 0;
55
halfword free_chain[MAX_CHAIN_SIZE] = { null };
57
static int my_prealloc = 0;
59
int fix_node_lists = 1;
61
int free_error_seen = 0;
62
int copy_error_seen = 0;
64
halfword slow_get_node(int s); /* defined below */
65
int copy_error(halfword p); /* define below */
68
#define fake_node_size 2
69
#define fake_node_name "fake"
71
#define variable_node_size 2
73
const char *node_fields_list[] =
74
{ "attr", "width", "depth", "height", "dir", "shift",
75
"glue_order", "glue_sign", "glue_set", "list", NULL
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 };
89
const char *node_fields_unset[] =
90
{ "attr", "width", "depth", "height", "dir", "shrink",
91
"glue_order", "glue_sign", "stretch", "span", "list", NULL
93
const char *node_fields_margin_kern[] = { "attr", "width", "glyph", NULL };
95
const char *node_fields_glyph[] =
96
{ "attr", "char", "font", "lang", "left", "right", "uchyph",
97
"components", "xoffset", "yoffset", "width", "height", "depth", "expansion_factor", NULL
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 };
127
const char *node_fields_inserting[] =
128
{ "height", "last_ins_ptr", "best_ins_ptr", NULL };
130
const char *node_fields_splitup[] = { "height", "last_ins_ptr", "best_ins_ptr",
131
"broken_ptr", "broken_ins", NULL
134
const char *node_fields_action[] = { "action_type", "named_id", "action_id",
135
"file", "new_window", "data", "ref_count", NULL
137
const char *node_fields_attribute[] = { "number", "value", NULL };
139
const char *node_fields_glue_spec[] = { "width", "stretch", "shrink",
140
"stretch_order", "shrink_order", "ref_count", "writable", NULL
142
const char *node_fields_attribute_list[] = { NULL };
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 };
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
154
const char *node_fields_whatsit_dir[] =
155
{ "attr", "dir", "level", "dvi_ptr", "dvi_h", NULL };
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
170
const char *node_fields_whatsit_pdf_end_link[] = { "attr", NULL };
172
const char *node_fields_whatsit_pdf_dest[] =
173
{ "attr", "width", "depth", "height",
174
"named_id", "dest_id", "dest_type", "xyz_zoom", "objnum", NULL
177
const char *node_fields_whatsit_pdf_thread[] =
178
{ "attr", "width", "depth", "height",
179
"named_id", "thread_id", "thread_attr", NULL
182
const char *node_fields_whatsit_pdf_start_thread[] =
183
{ "attr", "width", "depth", "height",
184
"named_id", "thread_id", "thread_attr", NULL
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 };
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,
237
{delim_node, math_shield_node_size, node_fields_delim, "delim"},
238
{margin_kern_node, margin_kern_node_size, node_fields_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,
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"},
266
#define last_normal_node shape_node
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,
277
{dir_node, dir_node_size, node_fields_whatsit_dir, "dir"},
278
{pdf_literal_node, write_node_size, node_fields_whatsit_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,
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,
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,
298
{pdf_thread_node, pdf_thread_node_size, node_fields_whatsit_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,
319
{close_lua_node, write_node_size, node_fields_whatsit_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,
329
{pdf_restore_node, pdf_restore_node_size, node_fields_whatsit_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"},
338
#define last_whatsit_node user_defined_node
341
halfword new_node(int i, int j)
345
s = get_node_size(i, j);
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)));
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);
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);
380
depth(n) = null_flag;
381
height(n) = null_flag;
385
width(n) = null_flag;
387
case pseudo_line_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()|.
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)));
401
/* handle synctex extension */
404
synctex_tag_math(n) = cur_input.synctex_tag_field;
405
synctex_line_math(n) = line;
408
synctex_tag_glue(n) = cur_input.synctex_tag_field;
409
synctex_line_glue(n) = line;
412
/* synctex ignores implicit kerns */
414
synctex_tag_kern(n) = cur_input.synctex_tag_field;
415
synctex_line_kern(n) = line;
421
synctex_tag_box(n) = cur_input.synctex_tag_field;
422
synctex_line_box(n) = line;
425
synctex_tag_rule(n) = cur_input.synctex_tag_field;
426
synctex_line_rule(n) = line;
429
/* take care of attributes */
430
if (nodetype_has_attributes(i)) {
431
build_attribute_list(n);
433
type(n) = (quarterword) i;
434
subtype(n) = (quarterword) j;
436
fprintf(DEBUG_OUT, "Alloc-ing %s node %d\n",
437
get_node_name(type(n), subtype(n)), (int) n);
442
halfword raw_glyph_node(void)
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;
453
halfword new_glyph_node(void)
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;
461
build_attribute_list(n);
466
@ makes a duplicate of the node list that starts at |p| and returns a
467
pointer to the new list
469
halfword do_copy_node_list(halfword p, halfword end)
471
halfword q = null; /* previous position in new list */
472
halfword h = null; /* head of the list */
475
register halfword s = copy_node(p);
487
halfword copy_node_list(halfword p)
489
return do_copy_node_list(p, null);
492
@ make a dupe of a single node
494
halfword copy_node(const halfword p)
496
halfword r; /* current node being fabricated for new list */
497
register halfword s; /* a helper variable for copying into variable mem */
500
r = new_node(temp_node, 0);
503
i = get_node_size(type(p), subtype(p));
506
(void) memcpy((void *) (varmem + r), (void *) (varmem + p),
507
(sizeof(memory_word) * (unsigned) i));
509
/* handle synctex extension */
512
synctex_tag_math(r) = cur_input.synctex_tag_field;
513
synctex_line_math(r) = line;
516
synctex_tag_kern(r) = cur_input.synctex_tag_field;
517
synctex_line_kern(r) = line;
521
if (nodetype_has_attributes(type(p))) {
522
add_node_attr_ref(node_attr(p));
523
alink(r) = null; /* needs checking */
530
s = copy_node_list(lig_ptr(p));
534
add_glue_ref(glue_ptr(p));
535
s = copy_node_list(leader_ptr(p));
541
s = copy_node_list(list_ptr(p));
545
add_glue_ref(split_top_ptr(p));
546
s = copy_node_list(ins_ptr(p));
549
case margin_kern_node:
550
s = copy_node(margin_char(p));
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;
561
assert(tlink(pre_break(r)) == null);
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;
570
assert(tlink_post_break(r) == null);
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;
579
assert(tlink_no_break(r) == null);
583
add_token_ref(mark_ptr(p));
586
s = copy_node_list(adjust_ptr(p));
591
s = copy_node_list(display_mlist(p));
592
display_mlist(r) = s;
593
s = copy_node_list(text_mlist(p));
595
s = copy_node_list(script_mlist(p));
597
s = copy_node_list(script_script_mlist(p));
598
script_script_mlist(r) = s;
603
s = copy_node_list(nucleus(p));
605
s = copy_node_list(subscr(p));
607
s = copy_node_list(supscr(p));
609
if (type(p) == accent_noad) {
610
s = copy_node_list(accent_chr(p));
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));
622
s = copy_node(delimiter(p));
627
s = copy_node_list(math_list(p));
631
s = copy_node_list(numerator(p));
633
s = copy_node_list(denominator(p));
635
s = copy_node(left_delimiter(p));
636
left_delimiter(r) = s;
637
s = copy_node(right_delimiter(p));
638
right_delimiter(r) = s;
641
glue_ref_count(r) = null;
644
switch (subtype(p)) {
650
add_token_ref(write_tokens(p));
652
case pdf_literal_node:
653
copy_pdf_literal(r, p);
655
case pdf_colorstack_node:
656
if (pdf_colorstack_cmd(p) <= colorstack_data)
657
add_token_ref(pdf_colorstack_data(p));
659
case pdf_setmatrix_node:
660
add_token_ref(pdf_setmatrix_data(p));
663
if (late_lua_name(p) > 0)
664
add_token_ref(late_lua_name(p));
665
add_token_ref(late_lua_data(p));
668
add_token_ref(pdf_annot_data(p));
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));
676
if (pdf_dest_named_id(p) > 0)
677
add_token_ref(pdf_dest_id(p));
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));
686
case user_defined_node:
687
switch (user_node_type(p)) {
689
add_node_attr_ref(user_node_value(p));
692
add_token_ref(user_node_value(p));
695
/* |add_string_ref(user_node_value(p));| *//* if this was mpost .. */
698
s = copy_node_list(user_node_value(p));
699
user_node_value(r) = s;
707
case math_text_char_node:
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);
724
int valid_node(halfword p)
726
if (p > my_prealloc) {
727
if (p < var_mem_max) {
729
if (varmem_sizes[p] > 0)
740
static void do_free_error(halfword p)
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.",
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);
763
snprintf(errstr, 255, "Attempt to double-free %s node %d, ignored",
764
get_node_name(type(p), subtype(p)), (int) p);
766
tex_error(errstr, errhlp);
768
for (r = my_prealloc + 1; r < var_mem_max; r++) {
771
while (s > my_prealloc && varmem_sizes[s] == 0)
776
&& (r - s) < get_node_size(type(s), subtype(s))
779
if (type(s) == disc_node) {
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");
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)
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));
813
fprintf(stdout, "\n");
815
if ((type(s) != penalty_node)
816
&& (type(s) != math_node)
817
&& (type(s) != kern_node)
819
fprintf(stdout, " pointed to from %s node %d\n",
820
get_node_name(type(s), subtype(s)),
831
static int free_error(halfword p)
833
assert(p > my_prealloc);
834
assert(p < var_mem_max);
836
if (varmem_sizes[p] == 0) {
838
return 1; /* double free */
846
static void do_copy_error(halfword p)
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.",
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);
866
snprintf(errstr, 255, "Attempt to copy free %s node %d, ignored",
867
get_node_name(type(p), subtype(p)), (int) p);
869
tex_error(errstr, errhlp);
873
int copy_error(halfword p)
876
assert(p < var_mem_max);
878
if (p > my_prealloc && varmem_sizes[p] == 0) {
880
return 1; /* copy free node */
888
void flush_node(halfword p)
891
if (p == null) /* legal, but no-op */
895
fprintf(DEBUG_OUT, "Free-ing %s node %d\n",
896
get_node_name(type(p), subtype(p)), (int) p);
903
flush_node_list(lig_ptr(p));
906
delete_glue_ref(glue_ptr(p));
907
flush_node_list(leader_ptr(p));
911
case attribute_list_node:
923
flush_node_list(list_ptr(p));
926
switch (subtype(p)) {
934
case pdf_restore_node:
935
case cancel_boundary_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:
947
delete_token_ref(write_tokens(p));
949
case pdf_literal_node:
952
case pdf_colorstack_node:
953
if (pdf_colorstack_cmd(p) <= colorstack_data)
954
delete_token_ref(pdf_colorstack_data(p));
956
case pdf_setmatrix_node:
957
delete_token_ref(pdf_setmatrix_data(p));
960
if (late_lua_name(p) > 0)
961
delete_token_ref(late_lua_name(p));
962
delete_token_ref(late_lua_data(p));
965
delete_token_ref(pdf_annot_data(p));
968
case pdf_link_data_node:
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));
977
if (pdf_dest_named_id(p) > 0)
978
delete_token_ref(pdf_dest_id(p));
981
case pdf_thread_data_node:
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));
991
case user_defined_node:
992
switch (user_node_type(p)) {
994
delete_attribute_ref(user_node_value(p));
997
delete_token_ref(user_node_value(p));
1000
flush_node_list(user_node_value(p));
1003
/* |delete_string_ref(user_node_value(p));| *//* if this was mpost .. */
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.",
1016
tex_error("Unidentified user defined whatsit", hlp);
1029
flush_node_list(ins_ptr(p));
1030
delete_glue_ref(split_top_ptr(p));
1032
case margin_kern_node:
1033
flush_node(margin_char(p));
1036
delete_token_ref(mark_ptr(p));
1039
flush_node_list(vlink(pre_break(p)));
1040
flush_node_list(vlink(post_break(p)));
1041
flush_node_list(vlink(no_break(p)));
1044
flush_node_list(adjust_ptr(p));
1046
case style_node: /* nothing to do */
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));
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));
1069
flush_node(delimiter(p));
1071
case delim_node: /* nothing to do */
1072
case math_char_node:
1073
case math_text_char_node:
1076
case sub_mlist_node:
1077
flush_node_list(math_list(p));
1080
flush_node_list(numerator(p));
1081
flush_node_list(denominator(p));
1082
flush_node(left_delimiter(p));
1083
flush_node(right_delimiter(p));
1085
case pseudo_file_node:
1086
flush_node_list(pseudo_lines(p));
1088
case pseudo_line_node:
1090
free_node(p, subtype(p));
1093
case align_stack_node:
1098
case unhyphenated_node:
1099
case hyphenated_node:
1103
case inserting_node:
1108
fprintf(stdout, "flush_node: type is %d\n", type(p));
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)));
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 */
1129
register halfword q = vlink(p);
1136
static int test_count = 1;
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"); \
1145
#define dotest(a,b,c) do { \
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"); \
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)
1157
void check_node(halfword p)
1162
dorangetest(p, lig_ptr(p), var_mem_max);
1165
check_glue_ref(glue_ptr(p));
1166
dorangetest(p, leader_ptr(p), var_mem_max);
1171
case align_record_node:
1172
dorangetest(p, list_ptr(p), var_mem_max);
1175
dorangetest(p, ins_ptr(p), var_mem_max);
1176
check_glue_ref(split_top_ptr(p));
1179
switch (subtype(p)) {
1181
check_token_ref(write_tokens(p));
1183
case pdf_literal_node:
1184
if (pdf_literal_type(p) == normal)
1185
check_token_ref(pdf_literal_data(p));
1187
case pdf_colorstack_node:
1188
if (pdf_colorstack_cmd(p) <= colorstack_data)
1189
check_token_ref(pdf_colorstack_data(p));
1191
case pdf_setmatrix_node:
1192
check_token_ref(pdf_setmatrix_data(p));
1195
if (late_lua_name(p) > 0)
1196
check_token_ref(late_lua_name(p));
1197
check_token_ref(late_lua_data(p));
1199
case pdf_annot_node:
1200
check_token_ref(pdf_annot_data(p));
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));
1208
if (pdf_dest_named_id(p) > 0)
1209
check_token_ref(pdf_dest_id(p));
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));
1218
case user_defined_node:
1219
switch (user_node_type(p)) {
1221
check_attribute_ref(user_node_value(p));
1224
check_token_ref(user_node_value(p));
1227
dorangetest(p, user_node_value(p), var_mem_max);
1233
confusion("extuser");
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:
1257
case margin_kern_node:
1258
check_node(margin_char(p));
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);
1266
dorangetest(p, adjust_ptr(p), var_mem_max);
1268
case pseudo_file_node:
1269
dorangetest(p, pseudo_lines(p), var_mem_max);
1271
case pseudo_line_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);
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);
1287
dorangetest(p, nucleus(p), var_mem_max);
1288
dorangetest(p, subscr(p), var_mem_max);
1289
dorangetest(p, supscr(p), var_mem_max);
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);
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);
1306
dorangetest(p, delimiter(p), var_mem_max);
1314
case attribute_list_node:
1315
case attribute_node:
1316
case glue_spec_node:
1318
case align_stack_node:
1323
case unhyphenated_node:
1324
case hyphenated_node:
1330
fprintf(stdout, "check_node: type is %d\n", type(p));
1335
static void check_static_node_mem(void)
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);
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);
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);
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);
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);
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);
1387
void check_node_mem(void)
1390
check_static_node_mem();
1392
for (i = (my_prealloc + 1); i < var_mem_max; i++) {
1393
if (varmem_sizes[i] > 0) {
1402
void fix_node_list(halfword head)
1417
halfword get_node(int s)
1419
register halfword r;
1421
check_static_node_mem();
1423
assert(s < MAX_CHAIN_SIZE);
1427
free_chain[s] = vlink(r);
1429
varmem_sizes[r] = (char) s;
1432
var_used += s; /* maintain usage statistics */
1435
/* this is the end of the 'inner loop' */
1436
return slow_get_node(s);
1441
static void print_free_chain(int c)
1443
halfword p = free_chain[c];
1444
fprintf(stdout, "\nfree chain[%d] =\n ", c);
1446
fprintf(stdout, "%d,", (int) p);
1449
fprintf(stdout, "null;\n");
1454
void free_node(halfword p, int s)
1457
if (p <= my_prealloc) {
1458
fprintf(stdout, "node %d (type %d) should not be freed!\n", (int) p,
1463
varmem_sizes[p] = 0;
1465
if (s < MAX_CHAIN_SIZE) {
1466
vlink(p) = free_chain[s];
1469
/* todo ? it is perhaps possible to merge this node with an existing rover */
1472
while (vlink(rover) != vlink(p)) {
1473
rover = vlink(rover);
1477
var_used -= s; /* maintain statistics */
1481
static void free_node_chain(halfword q, int s)
1483
register halfword p = q;
1484
while (vlink(p) != null) {
1486
varmem_sizes[p] = 0;
1493
varmem_sizes[p] = 0;
1495
vlink(p) = free_chain[s];
1501
void init_node_mem(int t)
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);
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);
1513
memset((void *) (varmem), 0, (unsigned) t * sizeof(memory_word));
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);
1520
memset((void *) varmem_sizes, 0, sizeof(char) * (unsigned) t);
1523
rover = var_mem_stat_max + 1;
1524
vlink(rover) = rover;
1525
node_size(rover) = (t - rover);
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;
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;
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;
1632
void dump_node_mem(void)
1634
dump_int(var_mem_max);
1636
dump_things(varmem[0], var_mem_max);
1638
dump_things(varmem_sizes[0], var_mem_max);
1640
dump_things(free_chain[0], MAX_CHAIN_SIZE);
1642
dump_int(my_prealloc);
1645
@ it makes sense to enlarge the varmem array immediately
1647
void undump_node_mem(void)
1652
var_mem_max = (x < 100000 ? 100000 : x);
1653
varmem = xmallocarray(memory_word, (unsigned) var_mem_max);
1655
memset ((void *)varmem,0,x*sizeof(memory_word));
1657
undump_things(varmem[0], x);
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);
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 */
1669
node_size(x) = (var_mem_max - x);
1670
while (vlink(rover) != vlink(x)) {
1671
rover = vlink(rover);
1678
void test_rovers(char *s)
1682
fprintf(stdout, "%s: {rover=%d,size=%d,link=%d}", s, r, node_size(r),
1684
while (vlink(r) != q) {
1686
fprintf(stdout, ",{rover=%d,size=%d,link=%d}", r, node_size(r),
1689
fprintf(stdout, "\n");
1692
# define test_rovers(a)
1696
halfword slow_get_node(int s)
1701
t = node_size(rover);
1702
assert(vlink(rover) < var_mem_max);
1703
assert(vlink(rover) != 0);
1704
test_rovers("entry");
1706
register halfword r;
1707
/* allocating from the bottom helps decrease page faults */
1710
vlink(rover) = vlink(r);
1711
node_size(rover) = node_size(r) - s;
1712
if (vlink(rover) != r) { /* list is longer than one */
1714
while (vlink(q) != r) {
1721
test_rovers("taken");
1722
assert(vlink(rover) < var_mem_max);
1724
varmem_sizes[r] = (char) (s > 127 ? 127 : s);
1727
var_used += s; /* maintain usage statistics */
1728
return r; /* this is the only exit */
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;
1738
while (vlink(l) != free_chain[t]) {
1742
test_rovers("outtake");
1746
while (vlink(rover) != l) {
1747
if (node_size(rover) > s) {
1750
rover = vlink(rover);
1754
/* if we are still here, it was apparently impossible to get a match */
1755
x = (var_mem_max >> 2) + s;
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);
1763
memset((void *) (varmem + var_mem_max), 0,
1764
(unsigned) x * sizeof(memory_word));
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);
1773
memset((void *) (varmem_sizes + var_mem_max), 0,
1774
(unsigned) (x) * sizeof(char));
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);
1783
vlink(rover) = var_mem_max;
1784
rover = var_mem_max;
1785
test_rovers("realloc");
1792
char *sprint_node_mem_usage(void)
1799
int node_counts[last_normal_node + last_whatsit_node + 2] = { 0 };
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)]++;
1808
node_counts[type(i)]++;
1814
for (i = 0; i < last_normal_node + last_whatsit_node + 2; i++) {
1815
if (node_counts[i] > 0) {
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),
1821
ss = xmalloc((unsigned) (strlen(s) + strlen(msg) + 1));
1836
halfword list_node_mem_usage(void)
1839
halfword p = null, q = null;
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) {
1854
free(saved_varmem_sizes);
1860
void print_node_mem_stats(void)
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));
1870
s = sprint_node_mem_usage();
1875
tprint_nl(" avail lists: ");
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]);
1887
print_nlp(); /* newline, if needed */
1890
/* this belongs in the web but i couldn't find the correct syntactic place */
1892
halfword new_span_node(halfword n, int s, scaled w)
1894
halfword p = new_node(span_node, 0);
1904
static halfword new_attribute_node(unsigned int i, int v)
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;
1914
halfword copy_attribute_list(halfword n)
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;
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));
1934
void update_attribute_cache(void)
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);
1950
if (vlink(attr_list_cache) == null) {
1951
free_node(attr_list_cache, attribute_node_size);
1952
attr_list_cache = null;
1958
void build_attribute_list(halfword b)
1960
if (max_used_attr >= 0) {
1961
if (attr_list_cache == cache_disabled) {
1962
update_attribute_cache();
1963
if (attr_list_cache == null)
1966
attr_list_ref(attr_list_cache)++;
1967
node_attr(b) = attr_list_cache;
1969
fprintf(DEBUG_OUT, "Added attrlist (%d) to node %d (count=%d)\n",
1970
node_attr(b), b, attr_list_ref(attr_list_cache));
1976
void delete_attribute_ref(halfword b)
1979
assert(type(b) == attribute_list_node);
1982
fprintf(DEBUG_OUT, "Removed attrlistref (%d) (count=%d)\n", b,
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);
1990
/* maintain sanity */
1991
if (attr_list_ref(b) < 0)
1992
attr_list_ref(b) = 0;
1996
@ |p| is an attr list head, or zero
1998
halfword do_set_attribute(halfword p, int i, int val)
2000
register halfword q;
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);
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 */
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);
2036
void set_attribute(halfword n, int i, int val)
2038
register halfword p;
2040
if (!nodetype_has_attributes(type(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;
2048
p = new_attribute_node((unsigned) i, val);
2049
vlink(node_attr(n)) = p;
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)
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));
2070
"Node %d has an attribute list that is free already\n",
2073
attr_list_ref(p) = 1;
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);
2090
int unset_attribute(halfword n, int i, int val)
2092
register halfword p;
2096
if (!nodetype_has_attributes(type(n)))
2100
return UNUSED_ATTRIBUTE;
2101
if (attr_list_ref(p) == 0) {
2103
"Node %d has an attribute list that is free already\n",
2105
return UNUSED_ATTRIBUTE;
2107
assert(vlink(p) != null);
2108
while (vlink(p) != null) {
2109
t = attribute_id(vlink(p));
2111
return UNUSED_ATTRIBUTE;
2119
if (attribute_id(p) != i)
2120
return UNUSED_ATTRIBUTE;
2121
/* if we are still here, the attribute exists */
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));
2128
attr_list_ref(q) = 1;
2131
p = vlink(node_attr(n));
2134
t = attribute_value(p);
2135
if (val == UNUSED_ATTRIBUTE || t == val) {
2136
attribute_value(p) = UNUSED_ATTRIBUTE;
2142
int has_attribute(halfword n, int i, int val)
2144
register halfword p;
2145
if (!nodetype_has_attributes(type(n)))
2146
return UNUSED_ATTRIBUTE;
2148
if (p == null || vlink(p) == null)
2149
return UNUSED_ATTRIBUTE;
2152
if (attribute_id(p) == i) {
2153
int ret = attribute_value(p);
2154
if (val == UNUSED_ATTRIBUTE || val == ret)
2156
return UNUSED_ATTRIBUTE;
2157
} else if (attribute_id(p) > i) {
2158
return UNUSED_ATTRIBUTE;
2162
return UNUSED_ATTRIBUTE;
2166
void print_short_node_contents(halfword p)
2183
if (glue_ptr(p) != zero_glue)
2190
short_display(vlink(pre_break(p)));
2191
short_display(vlink(post_break(p)));
2201
static void show_pdftex_whatsit_rule_spec(int p)
2204
print_rule_dimen(height(p));
2206
print_rule_dimen(depth(p));
2208
print_rule_dimen(width(p));
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.
2219
static void print_write_whatsit(const char *s, pointer p)
2222
if (write_stream(p) < 16)
2223
print_int(write_stream(p));
2224
else if (write_stream(p) == 16)
2232
static void show_whatsit_node(int p)
2234
switch (subtype(p)) {
2236
print_write_whatsit("openout", p);
2238
print_file_name(open_name(p), open_area(p), open_ext(p));
2241
print_write_whatsit("write", p);
2242
print_mark(write_tokens(p));
2245
print_write_whatsit("closeout", p);
2248
tprint_esc("special");
2249
print_mark(write_tokens(p));
2252
if (dir_dir(p) < 0) {
2253
tprint_esc("enddir");
2255
print_dir(dir_dir(p) + 64);
2257
tprint_esc("begindir");
2259
print_dir(dir_dir(p));
2262
case local_par_node:
2263
tprint_esc("whatsit");
2266
print_current_string();
2267
tprint_esc("localinterlinepenalty");
2269
print_int(local_pen_inter(p));
2271
print_current_string();
2272
tprint_esc("localbrokenpenalty");
2274
print_int(local_pen_broken(p));
2276
print_current_string();
2277
tprint_esc("localleftbox");
2278
if (local_box_left(p) == null) {
2282
show_node_list(local_box_left(p));
2286
print_current_string();
2287
tprint_esc("localrightbox");
2288
if (local_box_right(p) == null) {
2292
show_node_list(local_box_right(p));
2297
case pdf_literal_node:
2298
show_pdf_literal(p);
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:
2307
case colorstack_push:
2310
case colorstack_pop:
2313
case colorstack_current:
2317
confusion("pdfcolorstack");
2320
if (pdf_colorstack_cmd(p) <= colorstack_data)
2321
print_mark(pdf_colorstack_data(p));
2323
case pdf_setmatrix_node:
2324
tprint_esc("pdfsetmatrix");
2325
print_mark(pdf_setmatrix_data(p));
2328
tprint_esc("pdfsave");
2330
case pdf_restore_node:
2331
tprint_esc("pdfrestore");
2333
case cancel_boundary_node:
2334
tprint_esc("noboundary");
2337
tprint_esc("latelua");
2338
print_int(late_lua_reg(p));
2339
print_mark(late_lua_data(p));
2341
case close_lua_node:
2342
tprint_esc("closelua");
2343
print_int(late_lua_reg(p));
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) {
2350
lua_rawgeti(Luas, LUA_REGISTRYINDEX,
2351
obj_obj_stream_attr(static_pdf, pdf_obj_objnum(p)));
2353
tprint((const char *) lua_tostring(Luas, -1));
2358
if (obj_obj_is_file(static_pdf, pdf_obj_objnum(p)))
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)));
2364
tprint((const char *) lua_tostring(Luas, -1));
2368
case pdf_refxform_node:
2369
case pdf_refximage_node:
2370
if (subtype(p) == pdf_refxform_node)
2371
tprint_esc("pdfrefxform");
2373
tprint_esc("pdfrefximage");
2375
print_scaled(height(p));
2377
print_scaled(depth(p));
2379
print_scaled(width(p));
2381
case pdf_annot_node:
2382
tprint_esc("pdfannot");
2383
show_pdftex_whatsit_rule_spec(p);
2384
print_mark(pdf_annot_data(p));
2386
case pdf_start_link_node:
2387
tprint_esc("pdfstartlink");
2388
show_pdftex_whatsit_rule_spec(p);
2389
if (pdf_link_attr(p) != null) {
2391
print_mark(pdf_link_attr(p));
2394
if (pdf_action_type(pdf_link_action(p)) == pdf_action_user) {
2396
print_mark(pdf_action_tokens(pdf_link_action(p)));
2399
if (pdf_action_file(pdf_link_action(p)) != null) {
2401
print_mark(pdf_action_file(pdf_link_action(p)));
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)));
2409
tprint(" goto num");
2410
print_int(pdf_action_id(pdf_link_action(p)));
2413
case pdf_action_page:
2415
print_int(pdf_action_id(pdf_link_action(p)));
2416
print_mark(pdf_action_tokens(pdf_link_action(p)));
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)));
2423
tprint(" thread num");
2424
print_int(pdf_action_id(pdf_link_action(p)));
2428
pdf_error("displaying", "unknown action type");
2432
case pdf_end_link_node:
2433
tprint_esc("pdfendlink");
2436
tprint_esc("pdfdest");
2437
if (pdf_dest_named_id(p) > 0) {
2439
print_mark(pdf_dest_id(p));
2442
print_int(pdf_dest_id(p));
2445
switch (pdf_dest_type(p)) {
2448
if (pdf_dest_xyz_zoom(p) != null) {
2450
print_int(pdf_dest_xyz_zoom(p));
2453
case pdf_dest_fitbh:
2456
case pdf_dest_fitbv:
2470
show_pdftex_whatsit_rule_spec(p);
2480
case pdf_thread_node:
2481
case pdf_start_thread_node:
2482
if (subtype(p) == pdf_thread_node)
2483
tprint_esc("pdfthread");
2485
tprint_esc("pdfstartthread");
2487
print_rule_dimen(height(p));
2489
print_rule_dimen(depth(p));
2491
print_rule_dimen(width(p));
2492
if (pdf_thread_attr(p) != null) {
2494
print_mark(pdf_thread_attr(p));
2496
if (pdf_thread_named_id(p) > 0) {
2498
print_mark(pdf_thread_id(p));
2501
print_int(pdf_thread_id(p));
2504
case pdf_end_thread_node:
2505
tprint_esc("pdfendthread");
2507
case pdf_save_pos_node:
2508
tprint_esc("pdfsavepos");
2510
case user_defined_node:
2511
tprint_esc("whatsit");
2512
print_int(user_node_id(p));
2514
switch (user_node_type(p)) {
2520
show_node_list(user_node_value(p));
2525
print(user_node_value(p));
2529
print_mark(user_node_value(p));
2531
default: /* only 'd' */
2532
print_int(user_node_value(p));
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.
2556
@ |str_room| need not be checked; see |show_box|
2558
@ Recursive calls on |show_node_list| therefore use the following pattern:
2560
#define node_list_display(A) do { \
2562
show_node_list(A); \
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) {
2572
tprint(" []"); /* indicate that there's been some truncation */
2578
print_current_string(); /* display the nesting history */
2579
if (int_par(tracing_online_code) < -2)
2582
if (n > breadth_max) { /* time to stop */
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))
2594
font_in_short_display = font(p);
2595
short_display(lig_ptr(p));
2596
if (is_rightboundary(p))
2605
/* Display box |p|; */
2606
if (type(p) == hlist_node)
2608
else if (type(p) == vlist_node)
2611
tprint_esc("unset");
2613
print_scaled(height(p));
2615
print_scaled(depth(p));
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) {
2622
print_int(span_count(p) + 1);
2623
tprint(" columns)");
2625
if (glue_stretch(p) != 0) {
2626
tprint(", stretch ");
2627
print_glue(glue_stretch(p), glue_order(p), NULL);
2629
if (glue_shrink(p) != 0) {
2630
tprint(", shrink ");
2631
print_glue(glue_shrink(p), glue_sign(p), NULL);
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.
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)
2649
if (g > 20000.0 || g < -20000.0) {
2654
print_glue(20000 * unity, glue_order(p), NULL);
2656
print_glue(round(unity * g), glue_order(p), NULL);
2660
if (shift_amount(p) != 0) {
2661
tprint(", shifted ");
2662
print_scaled(shift_amount(p));
2664
tprint(", direction ");
2665
print_dir(box_dir(p));
2667
node_list_display(list_ptr(p)); /* recursive call */
2670
/* Display rule |p|; */
2671
tprint_esc("rule(");
2672
print_rule_dimen(height(p));
2674
print_rule_dimen(depth(p));
2676
print_rule_dimen(width(p));
2679
/* Display insertion |p|; */
2680
tprint_esc("insert");
2681
print_int(subtype(p));
2682
tprint(", natural size ");
2683
print_scaled(height(p));
2685
print_spec(split_top_ptr(p), NULL);
2687
print_scaled(depth(p));
2688
tprint("); float cost ");
2689
print_int(float_cost(p));
2690
node_list_display(ins_ptr(p)); /* recursive call */
2693
show_whatsit_node(p);
2696
/* Display glue |p|; */
2697
if (subtype(p) >= a_leaders) {
2698
/* Display leaders |p|; */
2700
switch (subtype(p)) {
2716
print_spec(glue_ptr(p), NULL);
2717
node_list_display(leader_ptr(p)); /* recursive call */
2720
if (subtype(p) != normal) {
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");
2731
tprint_esc("mskip");
2735
if (subtype(p) != cond_math_glue) {
2737
if (subtype(p) < cond_math_glue)
2738
print_spec(glue_ptr(p), NULL);
2740
print_spec(glue_ptr(p), "mu");
2744
case margin_kern_node:
2746
print_scaled(width(p));
2747
if (subtype(p) == left_side)
2748
tprint(" (left margin)");
2750
tprint(" (right margin)");
2753
/* Display kern |p|; */
2754
/* An ``explicit'' kern value is indicated implicitly by an explicit space. */
2755
if (subtype(p) != mu_glue) {
2757
if (subtype(p) != normal)
2759
print_scaled(width(p));
2760
if (subtype(p) == acc_kern)
2761
tprint(" (for accent)");
2763
tprint_esc("mkern");
2764
print_scaled(width(p));
2769
/* Display math node |p|; */
2771
if (subtype(p) == before)
2775
if (width(p) != 0) {
2776
tprint(", surrounded ");
2777
print_scaled(width(p));
2781
/* Display penalty |p|; */
2782
tprint_esc("penalty ");
2783
print_int(penalty(p));
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)));
2794
node_list_display(vlink(pre_break(p))); /* recursive call */
2796
show_node_list(vlink(post_break(p)));
2797
flush_char(); /* recursive call */
2800
/* Display mark |p|; */
2802
if (mark_class(p) != 0) {
2804
print_int(mark_class(p));
2806
print_mark(mark_ptr(p));
2809
/* Display adjustment |p|; */
2810
tprint_esc("vadjust");
2811
if (adjust_pre(p) != 0)
2813
node_list_display(adjust_ptr(p)); /* recursive call */
2824
@ This routine finds the 'base' width of a horizontal box, using the same logic
2825
that \TeX82 used for \.{\\predisplaywidth} */
2828
pointer actual_box_width(pointer r, scaled base_width)
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 */
2837
v = shift_amount(r) + base_width;
2840
if (is_char_node(p)) {
2852
case margin_kern_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
2870
if (glue_sign(r) == stretching) {
2871
if ((glue_order(r) == stretch_order(q))
2872
&& (stretch(q) != 0))
2874
} else if (glue_sign(r) == shrinking) {
2875
if ((glue_order(r) == shrink_order(q))
2876
&& (shrink(q) != 0))
2879
if (subtype(p) >= a_leaders)
2883
if ((subtype(p) == pdf_refxform_node)
2884
|| (subtype(p) == pdf_refximage_node))
2897
if (v < max_dimen) {
2912
halfword tail_of_list(halfword p)
2915
while (vlink(q) != null)
2921
@ |delete_glue_ref| is called when a pointer to a glue
2922
specification is being withdrawn.
2925
#define fast_delete_glue_ref(A) do { \
2926
if (glue_ref_count(A)==null) { \
2929
decr(glue_ref_count(A)); \
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);
2941
halfword temp_ptr; /* a pointer variable for occasional emergency use */
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
2952
int max_used_attr; /* maximum assigned attribute id */
2953
halfword attr_list_cache;
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.
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|'.
2967
@ Character nodes appear only in horizontal lists, never in vertical lists.
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.
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|.
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;
3002
@ A |vlist_node| is like an |hlist_node| in all respects except that it
3003
contains a vertical list.
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.
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.
3018
halfword new_rule(void)
3020
halfword p; /* the new node */
3021
p = new_node(rule_node, 0); /* the |subtype| is not used */
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.
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.
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
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.
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.
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|).
3069
halfword new_glyph(int f, int c)
3071
halfword p = null; /* the new node */
3072
if ((f == 0) || (char_exists(f, c))) {
3073
p = new_glyph_node();
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.)
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|.
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.
3098
|main_control| inserts these, and they are later converted to
3099
|subtype_normal| by |new_ligkern|.
3102
quarterword norm_min(int h)
3109
return (quarterword) h;
3112
halfword new_char(int f, int c)
3114
halfword p; /* the new node */
3115
p = new_glyph_node();
3116
set_to_character(p);
3120
make_lang_data(uc_hyph, cur_lang, left_hyphen_min, right_hyphen_min);
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.
3129
@ Here are a few handy helpers used by the list output routines.
3132
scaled glyph_width(halfword p)
3135
w = char_width(font(p), character(p));
3139
scaled glyph_height(halfword p)
3142
w = char_height(font(p), character(p)) + y_displace(p);
3148
scaled glyph_depth(halfword p)
3151
w = char_depth(font(p), character(p));
3152
if (y_displace(p) > 0)
3153
w = w - y_displace(p);
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|.
3169
{TODO: Knuth said: All three of the discretionary texts must be lists
3170
that consist entirely of character, kern, box and rule nodes.}
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
3180
halfword new_disc(void)
3181
{ /* creates an empty |disc_node| */
3182
halfword p; /* the new node */
3183
p = new_node(disc_node, 0);
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.
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.
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}.
3209
halfword new_math(scaled w, int s)
3211
halfword p; /* the new node */
3212
p = new_node(math_node, s);
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.
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.
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.
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.
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
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.
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.
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.
3269
halfword new_spec(halfword p)
3270
{ /* duplicates a glue specification */
3271
halfword q; /* the new spec */
3273
glue_ref_count(q) = null;
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}.
3283
halfword new_param_glue(int n)
3285
halfword p; /* the new node */
3286
halfword q; /* the glue specification */
3287
p = new_node(glue_node, n + 1);
3290
incr(glue_ref_count(q));
3294
@ Glue nodes that are more or less anonymous are created by |new_glue|,
3295
whose argument points to a glue specification.
3298
halfword new_glue(halfword q)
3300
halfword p; /* the new node */
3301
p = new_node(glue_node, normal);
3303
incr(glue_ref_count(q));
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.
3315
halfword new_skip_param(int n)
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);
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).
3336
@ The |new_kern| function creates a kern node having a given width.
3339
halfword new_kern(scaled w)
3341
halfword p; /* the new node */
3342
p = new_node(kern_node, normal);
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.
3354
@ Anyone who has been reading the last few sections of the program will
3355
be able to guess what comes next.
3358
halfword new_penalty(int m)
3360
halfword p; /* the new node */
3361
p = new_node(penalty_node, 0); /* the |subtype| is not used */
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.
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.
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@>