home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mega Top 1
/
os2_top1.zip
/
os2_top1
/
APPS
/
TEKST
/
CMTEX330
/
SOURCE
/
PAGE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-02-19
|
21KB
|
1,070 lines
/*
* %Y%:%M%:%I%:%Q%
*
* Copyright 1987,1988,1991,1992 Pat J Monardo
*
* Redistribution of this file is permitted through
* the specifications in the file COPYING.
*
*
*/
#ifndef lint
static char *sccsid = "%A%";
#endif
#include "tex.h"
ptr contrib_head;
ptr page_ins_head;
ptr page_head;
ptr page_tail;
int page_contents;
scal page_so_far[8];
scal page_max_depth;
ptr last_glue;
scal last_kern;
int last_penalty;
bool output_active;
int insert_penalties;
int least_page_cost;
ptr best_page_break;
scal best_size;
scal best_height_plus_depth;
#define set_page_so_far_zero(P) (page_so_far[P] = 0)
#define set_height_zero(H) (active_height[H] = 0)
void
build_page ()
{
int pi, b, c;
ptr p, q, r;
#define INF_SHRINK_PAGE "Infinite glue shrinkage found on current page"
if (link(contrib_head) == null || output_active) {
return;
}
do {
p = link(contrib_head);
if (last_glue != null) {
delete_glue_ref(last_glue);
}
last_penalty = 0;
last_kern = 0;
if (type(p) == GLUE_NODE) {
last_glue = glue_ptr(p);
add_glue_ref(last_glue);
} else {
last_glue = null;
if (type(p) == PENALTY_NODE) {
last_penalty = penalty(p);
} else if (type(p) == KERN_NODE) {
last_kern = kern_width(p);
}
}
switch (type(p))
{
case HLIST_NODE:
case VLIST_NODE:
case RULE_NODE:
if (page_contents < BOX_THERE) {
if (page_contents == EMPTY) {
freeze_page_specs(BOX_THERE);
} else {
page_contents = BOX_THERE;
}
q = new_skip_param(TOP_SKIP_CODE);
link(q) = p;
link(contrib_head) = q;
r = glue_ptr(q);
if (glue_width(r) > box_height(p)) {
glue_width(r) -= box_height(p);
} else {
glue_width(r) = 0;
}
continue;
} else {
page_total += page_depth + box_height(p);
page_depth = box_depth(p);
goto contribute;
}
case GLUE_NODE:
if (page_contents < BOX_THERE) {
goto done;
} else if (precedes_break(page_tail)) {
pi = 0;
} else {
goto update_heights;
}
break;
case KERN_NODE:
if (page_contents < BOX_THERE) {
goto done;
} else if (link(p) == null) {
return;
} else if (type(link(p)) == GLUE_NODE) {
pi = 0;
} else {
goto update_heights;
}
break;
case PENALTY_NODE:
if (page_contents < BOX_THERE) {
goto done;
} else {
pi = penalty(p);
}
break;
case WHATSIT_NODE:
goto contribute;
case MARK_NODE:
goto contribute;
case INS_NODE:
insert_page(p);
goto contribute;
default:
confusion("page");
break;
}
if (pi < INF_PENALTY) {
b = page_badness();
if (b < AWFUL_BAD) {
if (pi <= EJECT_PENALTY) {
c = pi;
} else if (b < INF_BAD) {
c = b + pi + insert_penalties;
} else {
c = DEPLORABLE;
}
} else {
c = b;
}
if (insert_penalties >= 10000) {
c = AWFUL_BAD;
}
if (tracing_pages > 0) {
show_page_stats(b, pi, c);
}
if (c <= least_page_cost) {
best_page_break = p;
best_size = page_goal;
least_page_cost = c;
r = link(page_ins_head);
while (r != page_ins_head) {
best_ins_ptr(r) = last_ins_ptr(r);
r = link(r);
}
}
if (c == AWFUL_BAD || pi <= EJECT_PENALTY) {
fire_up(p);
if (output_active) {
return;
}
continue;
}
}
if (type(p) < GLUE_NODE || type(p) > KERN_NODE) {
goto contribute;
}
update_heights:
if (type(p) == KERN_NODE) {
page_total += page_depth + kern_width(p);
} else {
q = glue_ptr(p);
page_so_far[2 + stretch_order(q)] += stretch(q);
page_shrink += shrink(q);
if (shrink_order(q) != NORMAL && shrink(q) != 0) {
print_err(INF_SHRINK_PAGE);
help_inf_shrink_page();
error();
r = new_spec(q);
shrink_order(r) = NORMAL;
delete_glue_ref(q);
q = glue_ptr(p) = r;
}
page_total += page_depth + glue_width(q);
}
page_depth = 0;
contribute:
if (page_depth > page_max_depth) {
page_total = page_total + page_depth - page_max_depth;
page_depth = page_max_depth;
}
page_tail = link(page_tail) = p;
link(contrib_head) = link(p);
link(p) = null;
continue;
done:
link(contrib_head) = link(p);
link(p) = null;
flush_node_list(p);
} while (link(contrib_head) != null);
if (nest_ptr == nest) {
tail = contrib_head;
} else {
contrib_tail = contrib_head;
}
}
void
insert_page (p)
ptr p;
{
int n;
ptr q, r;
scal h, w;
scal delta;
if (page_contents == EMPTY) {
freeze_page_specs(INSERTS_ONLY);
}
n = subtype(p);
r = page_ins_head;
while (n >= subtype(link(r))) {
r = link(r);
}
if (subtype(r) != n) {
q = new_node(PAGE_INS_NODE_SIZE);
link(q) = link(r);
r = link(r) = q;
subtype(r) = n;
type(r) = INSERTING;
ensure_vbox(n);
page_ins_height(r) = (box(n) == null) ? 0 :
box_height(box(n)) + box_depth(box(n));
best_ins_ptr(r) = null;
q = skip(n);
if (count(n) == 1000) {
h = page_ins_height(r);
} else {
h = x_over_n(page_ins_height(r), 1000) * count(n);
}
page_goal -= h + glue_width(q);
page_so_far[2 + stretch_order(q)] += stretch(q);
page_shrink += shrink(q);
if (shrink_order(q) != NORMAL && shrink(q) != 0) {
print_err("Infinite glue shrinkage inserted from ");
print_esc("skip");
print_int(n);
help_inf_shrink_ins();
error();
}
}
if (type(r) == SPLIT_UP) {
insert_penalties += float_cost(p);
return;
}
last_ins_ptr(r) = p;
delta = page_goal - page_total - page_depth + page_shrink;
if (count(n) == 1000) {
h = ins_height(p);
} else {
h = x_over_n(ins_height(p), 1000) * count(n);
}
if ((h <= 0 || h <= delta)
&& ins_height(p) + page_ins_height(r) <= dimen(n)) {
page_goal -= h;
page_ins_height(r) += ins_height(p);
} else {
if (count(n) <= 0) {
w = MAX_DIMEN;
} else {
w = page_goal - page_total - page_depth;
if (count(n) != 1000) {
w = x_over_n(w, count(n)) * 1000;
}
}
if (w > dimen(n) - page_ins_height(r)) {
w = dimen(n) - page_ins_height(r);
}
q = vert_break(ins_ptr(p), w, ins_depth(p));
page_ins_height(r) += best_height_plus_depth;
if (tracing_pages > 0) {
show_split(n, w, q);
}
if (count(n) != 1000) {
best_height_plus_depth =
x_over_n(best_height_plus_depth, 1000) *
count(n);
}
page_goal -= best_height_plus_depth;
type(r) = SPLIT_UP;
broken_ptr(r) = q;
broken_ins(r) = p;
if (q == null) {
insert_penalties += EJECT_PENALTY;
} else if (type(q) == PENALTY_NODE) {
insert_penalties += penalty(q);
}
}
}
ptr
vert_break (p, h, d)
ptr p;
scal h;
scal d;
{
int b;
ptr q;
ptr r;
int t;
int pi;
ptr prev_p;
scal prev_dp;
ptr best_place;
int least_cost;
#define INF_SHRINK_BOX "Infinite glue shrinkage found in box being split"
prev_p = p;
least_cost = AWFUL_BAD;
do_all_six(set_height_zero);
prev_dp = 0;
loop {
if (p == null) {
pi = EJECT_PENALTY;
} else {
switch (type(p))
{
case HLIST_NODE:
case VLIST_NODE:
case RULE_NODE:
cur_height += prev_dp + box_height(p);
prev_dp = box_depth(p);
goto not_found;
case WHATSIT_NODE:
goto not_found;
case GLUE_NODE:
if (precedes_break(prev_p)) {
pi = 0;
} else {
goto update_heights;
}
break;
case KERN_NODE:
if (link(p) == null) {
t = PENALTY_NODE;
} else {
t = type(link(p));
}
if (t == GLUE_NODE) {
pi = 0;
} else {
goto update_heights;
}
break;
case PENALTY_NODE:
pi = penalty(p);
break;
case MARK_NODE:
case INS_NODE:
goto not_found;
default:
confusion("vertbreak");
}
}
if (pi < INF_PENALTY) {
b = vert_badness(h);
if (b < AWFUL_BAD) {
if (pi <= EJECT_PENALTY) {
b = pi;
} else if (b < INF_BAD) {
b += pi;
} else {
b = DEPLORABLE;
}
}
if (b <= least_cost) {
best_place = p;
least_cost = b;
best_height_plus_depth = cur_height + prev_dp;
}
if (b == AWFUL_BAD || pi <= EJECT_PENALTY) {
return best_place;
}
}
if (type(p) < GLUE_NODE || type(p) > KERN_NODE) {
goto not_found;
}
update_heights:
if (type(p) == KERN_NODE) {
cur_height += prev_dp + kern_width(p);
} else {
q = glue_ptr(p);
active_height[2 + stretch_order(q)] += stretch(q);
active_height[6] += shrink(q);
if (shrink_order(q) != NORMAL && shrink(q) != 0) {
print_err(INF_SHRINK_BOX);
help_inf_shrink_box();
error();
r = new_spec(q);
delete_glue_ref(q);
shrink_order(r) = NORMAL;
glue_ptr(p) = r;
}
cur_height += prev_dp + glue_width(q);
}
prev_dp = 0;
not_found:
if (prev_dp > d) {
cur_height = cur_height + prev_dp - d;
prev_dp = d;
}
prev_p = p;
p = link(prev_p);
}
}
ptr
vsplit (n, h)
int n;
scal h;
{
ptr p;
ptr q;
ptr v;
v = box(n);
if (split_first_mark != null) {
delete_token_ref(split_first_mark);
split_first_mark = null;
delete_token_ref(split_bot_mark);
split_bot_mark = null;
}
if (v == null) {
return null;
}
if (type(v) != VLIST_NODE) {
print_err(null_str);
print_esc("vsplit");
print(" needs a ");
print_esc("vbox");
help_vsplit_vbox();
error();
return null;
}
q = vert_break(list_ptr(v), h, split_max_depth);
p = list_ptr(v);
if (p == q) {
list_ptr(v) = null;
} else {
loop {
if (type(p) == MARK_NODE) {
if (split_first_mark == null) {
split_first_mark = mark_ptr(p);
split_bot_mark = split_first_mark;
token_ref_count(split_first_mark) += 2;
} else {
delete_token_ref(split_bot_mark);
split_bot_mark = mark_ptr(p);
add_token_ref(split_bot_mark);
}
}
if (link(p) == q) {
link(p) = null;
break;
}
p = link(p);
}
}
q = prune_page_top(q);
p = list_ptr(v);
free_node(v, BOX_NODE_SIZE);
if (q == null) {
box(n) = null;
} else {
box(n) = vpack(q, NATURAL);
}
return (vpackage(p, h, EXACTLY, split_max_depth));
}
ptr
prune_page_top (p)
ptr p;
{
mcell m;
ptr prev_p;
ptr q, s, t;
t = (ptr)&m;
prev_p = t;
link(t) = p;
while (p != null) {
switch (type(p))
{
case HLIST_NODE:
case VLIST_NODE:
case RULE_NODE:
q = new_skip_param(SPLIT_TOP_SKIP_CODE);
link(prev_p) = q;
link(q) = p;
s = glue_ptr(q);
if (glue_width(s) > box_height(p)) {
glue_width(s) -= box_height(p);
} else {
glue_width(s) = 0;
}
p = null;
break;
case WHATSIT_NODE:
case MARK_NODE:
case INS_NODE:
prev_p = p;
p = link(p);
break;
case GLUE_NODE:
case KERN_NODE:
case PENALTY_NODE:
q = p;
p = link(p);
link(q) = null;
link(prev_p) = p;
flush_node_list(q);
break;
default:
confusion("pruning");
break;
}
}
return (link(t));
}
int
page_badness ()
{
int b;
if (page_total < page_goal) {
if (page_so_far[3] != 0
|| page_so_far[4] != 0
|| page_so_far[5] != 0) {
b = 0;
} else {
b = badness(page_goal - page_total, page_so_far[2]);
}
} else if (page_total - page_goal > page_shrink) {
b = AWFUL_BAD;
} else {
b = badness(page_total - page_goal, page_shrink);
}
return b;
}
int
vert_badness (height)
int height;
{
int b;
if (cur_height < height) {
if (active_height[3] != 0
|| active_height[4] != 0
|| active_height[5] != 0) {
b = 0;
} else {
b = badness(height - cur_height, active_height[2]);
}
} else if (cur_height - height > active_height[6]) {
b = AWFUL_BAD;
} else {
b = badness(cur_height - height, active_height[6]);
}
return b;
}
void
freeze_page_specs (s)
int s;
{
page_contents = s;
page_goal = vsize;
page_max_depth = max_depth;
page_depth = 0;
do_all_six(set_page_so_far_zero);
least_page_cost = AWFUL_BAD;
if (tracing_pages > 0) {
begin_diagnostic();
print_nl("%% goal height=");
print_scaled(page_goal);
print(", max depth=");
print_scaled(page_max_depth);
end_diagnostic(FALSE);
}
}
void
box_error (n)
int n;
{
error();
begin_diagnostic();
print_nl("The following box has been deleted:");
show_box(box(n));
end_diagnostic(TRUE);
flush_node_list(box(n));
box(n) = null;
}
void
ensure_vbox (n)
int n;
{
ptr p;
p = box(n);
if (p != null && type(p) == HLIST_NODE) {
print_err("Insertions can only be added to a vbox");
help_tut();
box_error(n);
}
}
void
print_plus (s, o)
int s;
str o;
{
if (page_so_far[s] != 0) {
print(" plus ");
print_scaled(page_so_far[s]);
print(o);
}
}
void
print_totals ()
{
print_scaled(page_total);
print_plus(2, null_str);
print_plus(3, "fil");
print_plus(4, "fill");
print_plus(5, "filll");
if (page_shrink != 0) {
print(" minus ");
print_scaled(page_shrink);
}
}
void
show_split(n, w, q)
int n;
scal w;
ptr q;
{
begin_diagnostic();
print_nl("% split");
print_int(n);
print(" to ");
print_scaled(w);
print_char(',');
print_scaled(best_height_plus_depth);
print(" p=");
if (q == null) {
print_int(EJECT_PENALTY);
} else if (type(q) == PENALTY_NODE) {
print_int(penalty(q));
} else {
print("0");
}
end_diagnostic(FALSE);
}
void
show_page_stats (b, pi, c)
int b;
int pi;
int c;
{
begin_diagnostic();
print_nl("%");
print(" t=");
print_totals();
print(" g=");
print_scaled(page_goal);
print(" b=");
if (b == AWFUL_BAD) {
print_char('*');
} else {
print_int(b);
}
print(" p=");
print_int(pi);
print(" c=");
if (c == AWFUL_BAD) {
print("*");
} else {
print_int(c);
}
if (c <= least_page_cost) {
print("#");
}
end_diagnostic(FALSE);
}
#define set_output_penalty(P) \
reg_gdefine(int_reg[OUTPUT_PENALTY_CODE], INT_REG, P)
void
fire_up (c)
ptr c;
{
int n;
bool wait;
ptr prev_p;
scal save_vfuzz;
int save_vbadness;
ptr save_split_top_skip;
ptr p, q, r;
if (type(best_page_break) == PENALTY_NODE) {
set_output_penalty(penalty(best_page_break));
penalty(best_page_break) = INF_PENALTY;
} else {
set_output_penalty(INF_PENALTY);
}
if (bot_mark != null) {
if (top_mark != null) {
delete_token_ref(top_mark);
}
top_mark = bot_mark;
add_token_ref(top_mark);
delete_token_ref(first_mark);
first_mark = null;
}
if (c == best_page_break) {
best_page_break = null;
}
if (box(255) != null) {
print_err(null_str);
print_esc("box");
print("255 is not void");
help_box_255();
box_error(255);
}
insert_penalties = 0;
save_split_top_skip = split_top_skip;
if (holding_inserts <= 0) {
r = link(page_ins_head);
while (r != page_ins_head) {
if (best_ins_ptr(r) != null) {
n = subtype(r);
ensure_vbox(n);
if (box(n) == null) {
box(n) = new_null_box();
}
p = node_list(box(n));
while (link(p) != null) {
p = link(p);
}
last_ins_ptr(r) = p;
}
r = link(r);
}
}
q = hold_head;
link(q) = null;
prev_p = page_head;
p = link(prev_p);
while (p != best_page_break) {
if (type(p) == INS_NODE) {
if (holding_inserts <= 0) {
wait = insert_box(p);
link(prev_p) = link(p);
link(p) = null;
if (wait) {
q = link(q) = p;
incr(insert_penalties);
} else {
delete_glue_ref(split_top_ptr(p));
free_node(p, INS_NODE_SIZE);
}
p = prev_p;
}
} else if (type(p) == MARK_NODE) {
if (first_mark == null) {
first_mark = mark_ptr(p);
add_token_ref(first_mark);
}
if (bot_mark != null) {
delete_token_ref(bot_mark);
}
bot_mark = mark_ptr(p);
add_token_ref(bot_mark);
}
prev_p = p;
p = link(prev_p);
}
split_top_skip = save_split_top_skip;
if (p != null) {
if (link(contrib_head) == null) {
if (nest_ptr == nest) {
tail = page_tail;
} else {
contrib_tail = page_tail;
}
}
link(page_tail) = link(contrib_head);
link(contrib_head) = p;
link(prev_p) = null;
}
save_vbadness = vbadness;
save_vfuzz = vfuzz;
vbadness = INF_BAD;
vfuzz = MAX_DIMEN;
box(255) = vpackage(link(page_head),
best_size, EXACTLY, page_max_depth);
vbadness = save_vbadness;
vfuzz = save_vfuzz;
if (last_glue != null) {
delete_glue_ref(last_glue);
}
start_new_page();
if (q != hold_head) {
link(page_head) = link(hold_head);
page_tail = q;
}
r = link(page_ins_head);
while (r != page_ins_head) {
q = link(r);
free_node(r, PAGE_INS_NODE_SIZE);
r = q;
}
link(page_ins_head) = page_ins_head;
if (top_mark != null && first_mark == null) {
first_mark = top_mark;
add_token_ref(top_mark);
}
if (output_routine != null) {
if (dead_cycles >= max_dead_cycles) {
print_err("Output loop---");
print_int(dead_cycles);
print(" consecutive dead cycles");
help_dead_cycles();
error();
} else {
output_active = TRUE;
incr(dead_cycles);
push_nest();
mode = -VMODE;
prev_depth = IGNORE_DEPTH;
mode_line = -line;
begin_token_list(output_routine, OUTPUT_TEXT);
new_save_level(OUTPUT_GROUP);
normal_paragraph();
scan_left_brace();
return;
}
}
if (link(page_head) != null) {
if (link(contrib_head) == null) {
if (nest_ptr == nest) {
tail = page_tail;
} else {
contrib_tail = page_tail;
}
} else {
link(page_tail) = link(contrib_head);
}
link(contrib_head) = link(page_head);
link(page_head) = null;
page_tail = page_head;
}
ship_out(box(255));
box(255) = null;
}
bool
insert_box (p)
ptr p;
{
bool wait;
ptr q, r, t;
int n;
q = link(page_ins_head);
while (subtype(q) != subtype(p)) {
q = link(q);
}
if (best_ins_ptr(q) == null) {
return TRUE;
}
wait = FALSE;
r = last_ins_ptr(q);
link(r) = ins_ptr(p);
if (best_ins_ptr(q) == p) {
if (type(q) == SPLIT_UP
&& broken_ins(q) == p
&& broken_ptr(q) != null) {
while (link(r) != broken_ptr(q)) {
r = link(r);
}
link(r) = null;
split_top_skip = split_top_ptr(p);
ins_ptr(p) = prune_page_top(broken_ptr(q));
if (ins_ptr(p) != null) {
t = vpack(ins_ptr(p), NATURAL);
ins_height(p) = box_height(t) + box_depth(t);
free_node(t, BOX_NODE_SIZE);
wait = TRUE;
}
}
best_ins_ptr(q) = null;
n = subtype(q);
t = list_ptr(box(n));
free_node(box(n), BOX_NODE_SIZE);
box(n) = vpack(t, NATURAL);
} else {
while (link(r) != null) {
r = link(r);
}
last_ins_ptr(q) = r;
}
return wait;
}
void
show_cur_page ()
{
ptr p, q;
int t;
if (page_head == page_tail) {
return;
}
print_nl("### current page:");
if (output_active) {
print(" (held over for next output)");
}
show_box(link(page_head));
if (page_contents > EMPTY) {
print_nl("total height ");
print_totals();
print_nl(" goal height ");
print_scaled(page_goal);
p = link(page_ins_head);
while (p != page_ins_head) {
print_ln();
print_esc("insert");
t = subtype(p);
print_int(t);
print(" adds ");
t = x_over_n(page_ins_height(p), 1000) * count(t);
print_scaled(t);
if (type(p) == SPLIT_UP) {
q = page_head;
t = 0;
do {
q = link(q);
if (type(q) == INS_NODE
&& subtype(q) == subtype(p)) {
incr(t);
}
} while (q != broken_ins(p));
print(", #");
print_int(t);
print(" might split");
}
p = link(p);
}
}
}
void
_page_init ()
{
start_new_page();
prev_depth = IGNORE_DEPTH;
output_active = FALSE;
insert_penalties = 0;
}
void
_page_init_once ()
{
contrib_head = new_avail();
page_tail = page_head = new_glue(zero_glue);
page_ins_head = new_node(PAGE_INS_NODE_SIZE);
link(page_ins_head) = page_ins_head;
type(page_ins_head) = SPLIT_UP;
subtype(page_ins_head) = 255;
}
/*
** Help text
*/
help_tut ()
{
help3("Tut tut: You're trying to \\insert into a",
"\\box register that now contains an \\hbox.",
"Proceed, and I'll discard its present contents.");
}
help_vsplit_vbox ()
{
help2("The box you are trying to split is an \\hbox.",
"I can't split such a box, so I'll leave it alone.");
}
help_inf_shrink_ins ()
{
help3("The correction glue for page breaking with insertions",
"must have finite shrinkability. But you may proceed,",
"since the offensive shrinkability has been made finite.");
}
help_inf_shrink_box ()
{
help4("The box you are \\vsplitting contains some infinitely",
"shrinkable glue, e.g., `\\vss' or `\\vskip 0pt minus 1fil'.",
"Such glue doesn't belong there; but you can safely proceed,",
"since the offensive shrinkability has been made finite.");
}
help_inf_shrink_page ()
{
help4("The page about to be output contains some infinitely",
"shrinkable glue, e.g., `\\vss' or `\\vskip 0pt minus 1fil'.",
"Such glue doesn't belong there; but you can safely proceed,",
"since the offensive shrinkability has been made finite.");
}
help_box_255 ()
{
help2("You shouldn't use \\box255 except in \\output routines.",
"Proceed, and I'll discard its present contents.");
}
help_dead_cycles ()
{
help3("I've concluded that your \\output is awry; it never does a",
"\\shipout, so I'm shipping \\box255 out myself. Next time",
"increase \\maxdeadcycles if you want me to be more patient!");
}