Section 203: Copying boxes
Another recursive operation that acts on boxes is sometimes needed: Theprocedure copy_node_list returns a pointer to another node list that has the same structure and meaning as the original. Note that since glue specifications and token lists have reference counts, we need not make copies of them. Reference counts can never get too large to fit in a halfword, since each pointer to a node is in a different memory address, and the total number of memory addresses fits in a halfword.
(Well, there actually are also references from outside mem; if the save_stack is made arbitrarily large, it would theoretically be possible to break by overflowing a reference count. But who would want to do that?)
#define add_token_ref(X) incr(token_ref_count((X))) // new reference to a token list
#define add_glue_ref(X) incr(glue_ref_count((X))) // new reference to a glue spec
Section 204
The copying procedure copies words en masse without bothering to look at their individual fields. If the node format changes—for example, if the size is altered, or if some link field is moved to another relative position—then this code may need to be changed too.
// makes a duplicate of the node list that starts at |p|
// and returns a pointer to the new list
pointer copy_node_list(pointer p) {
pointer h; // temporary head of copied list
pointer q; // previous position in new list
pointer r = null; // current node being fabricated for new list
int words; // number of words remaining to be copied
h = get_avail();
q = h;
while(p != null) {
// << Make a copy of node |p| in node |r|, 205 >>
link(q) = r;
q = r;
p = link(p);
}
link(q) = null;
q = link(h);
free_avail(h);
return q;
}
Section 205
⟨ Make a copy of node p in node r 205 ⟩≡
words = 1; // this setting occurs in more branches than any other
if (is_char_node(p)) {
r = get_avail();
}
else {
// << Case statement to copy different types and set |words| to the number of initial words not yet copied, 206 >>
}
while (words > 0) {
decr(words);
mem[r + words] = mem[p + words];
}
Section 206
⟨ Case statement to copy different types and set words to the number of initial words not yet copied 206 ⟩≡
switch(type(p)) {
case HLIST_NODE:
case VLIST_NODE:
case UNSET_NODE:
r = get_node(BOX_NODE_SIZE);
mem[r + 6] = mem[p + 6];
mem[r + 5] = mem[p + 5]; // copy the last two words
list_ptr(r) = copy_node_list(list_ptr(p)); // this affects |mem[r+5]|
words = 5;
break;
case RULE_NODE:
r = get_node(RULE_NODE_SIZE);
words = RULE_NODE_SIZE;
break;
case INS_NODE:
r = get_node(INS_NODE_SIZE);
mem[r + 4] = mem[p + 4];
add_glue_ref(split_top_ptr(p));
ins_ptr(r) = copy_node_list(ins_ptr(p)); // this affects |mem[r+4]|
words = INS_NODE_SIZE - 1;
break;
case WHATSIT_NODE:
// << Make a partial copy of the whatsit node |p| and make |r| point to it; set |words| to the number of initial words not yet copied, 1357 >>
break;
case GLUE_NODE:
r = get_node(SMALL_NODE_SIZE);
add_glue_ref(glue_ptr(p));
glue_ptr(r) = glue_ptr(p);
leader_ptr(r) = copy_node_list(leader_ptr(p));
break;
case KERN_NODE:
case MATH_NODE:
case PENALTY_NODE:
r = get_node(SMALL_NODE_SIZE);
words = SMALL_NODE_SIZE;
break;
case LIGATURE_NODE:
r = get_node(SMALL_NODE_SIZE);
mem[lig_char(r)] = mem[lig_char(p)]; // copy font and character
lig_ptr(r) = copy_node_list(lig_ptr(p));
break;
case DISC_NODE:
r = get_node(SMALL_NODE_SIZE);
pre_break(r) = copy_node_list(pre_break(p));
post_break(r) = copy_node_list(post_break(p));
break;
case MARK_NODE:
r = get_node(SMALL_NODE_SIZE);
add_token_ref(mark_ptr(p));
words = SMALL_NODE_SIZE;
break;
case ADJUST_NODE:
r = get_node(SMALL_NODE_SIZE);
adjust_ptr(r) = copy_node_list(adjust_ptr(p));
// words = 1 = SMALL_NODE_SIZE - 1
break;
default:
confusion("copying");
}