home *** CD-ROM | disk | FTP | other *** search
/ Mega Top 1 / os2_top1.zip / os2_top1 / APPS / TEKST / CMTEX330 / SOURCE / PAGE.C < prev    next >
C/C++ Source or Header  |  1992-02-19  |  21KB  |  1,070 lines

  1.  
  2. /*
  3.  * %Y%:%M%:%I%:%Q%
  4.  *
  5.  * Copyright 1987,1988,1991,1992 Pat J Monardo
  6.  *
  7.  * Redistribution of this file is permitted through
  8.  * the specifications in the file COPYING.
  9.  *
  10.  *
  11.  */
  12.  
  13. #ifndef lint
  14. static char *sccsid = "%A%";
  15. #endif
  16.  
  17. #include "tex.h"
  18.  
  19. ptr    contrib_head;
  20. ptr    page_ins_head;
  21. ptr    page_head;
  22. ptr    page_tail;
  23. int    page_contents;
  24. scal    page_so_far[8];
  25. scal    page_max_depth;
  26. ptr    last_glue;
  27. scal    last_kern;
  28. int    last_penalty;
  29. bool    output_active;
  30. int    insert_penalties;
  31. int    least_page_cost;
  32. ptr    best_page_break;
  33. scal    best_size;
  34. scal    best_height_plus_depth;
  35.  
  36. #define set_page_so_far_zero(P)    (page_so_far[P] = 0)
  37. #define set_height_zero(H)    (active_height[H] = 0)
  38.  
  39. void
  40. build_page ()
  41. {
  42.     int    pi, b, c;
  43.     ptr    p, q, r;
  44.  
  45. #define INF_SHRINK_PAGE "Infinite glue shrinkage found on current page"
  46.     
  47.     if (link(contrib_head) == null || output_active) {
  48.         return;
  49.     }
  50.     do {
  51.         p = link(contrib_head);
  52.         if (last_glue != null) {
  53.             delete_glue_ref(last_glue);
  54.         }
  55.         last_penalty = 0;
  56.         last_kern = 0;
  57.         if (type(p) == GLUE_NODE) {
  58.             last_glue = glue_ptr(p);
  59.             add_glue_ref(last_glue);
  60.         } else {
  61.             last_glue = null;
  62.             if (type(p) == PENALTY_NODE) {
  63.                 last_penalty = penalty(p);
  64.             } else if (type(p) == KERN_NODE) {
  65.                 last_kern = kern_width(p);
  66.             }
  67.         }
  68.         switch (type(p))
  69.         {
  70.         case HLIST_NODE:
  71.         case VLIST_NODE:
  72.         case RULE_NODE:
  73.             if (page_contents < BOX_THERE) {
  74.                 if (page_contents == EMPTY) {
  75.                     freeze_page_specs(BOX_THERE);
  76.                 } else {
  77.                     page_contents = BOX_THERE;
  78.                 }
  79.                 q = new_skip_param(TOP_SKIP_CODE);
  80.                 link(q) = p;
  81.                 link(contrib_head) = q;
  82.                 r = glue_ptr(q);
  83.                 if (glue_width(r) > box_height(p)) {
  84.                     glue_width(r) -= box_height(p);
  85.                 } else {
  86.                     glue_width(r) = 0;
  87.                 }
  88.                 continue;
  89.             } else {
  90.                 page_total += page_depth + box_height(p);
  91.                 page_depth = box_depth(p);
  92.                 goto contribute;
  93.             }
  94.         
  95.         case GLUE_NODE:
  96.             if (page_contents < BOX_THERE) {
  97.                 goto done;
  98.             } else if (precedes_break(page_tail)) {
  99.                 pi = 0;
  100.             } else {
  101.                 goto update_heights;
  102.             }
  103.             break;
  104.         
  105.         case KERN_NODE:
  106.             if (page_contents < BOX_THERE) {
  107.                 goto done;
  108.             } else if (link(p) == null) {
  109.                 return;
  110.             } else if (type(link(p)) == GLUE_NODE) {
  111.                 pi = 0;
  112.             } else {
  113.                 goto update_heights;
  114.             }
  115.             break;
  116.         
  117.         case PENALTY_NODE:
  118.             if (page_contents < BOX_THERE) {
  119.                 goto done;
  120.             } else {
  121.                 pi = penalty(p);
  122.             }
  123.             break;
  124.  
  125.         case WHATSIT_NODE:
  126.             goto contribute;
  127.         
  128.         case MARK_NODE:
  129.             goto contribute;
  130.  
  131.         case INS_NODE:
  132.             insert_page(p);
  133.             goto contribute;
  134.         
  135.         default:
  136.             confusion("page");
  137.             break;
  138.         }
  139.         if (pi < INF_PENALTY) {
  140.             b = page_badness();
  141.             if (b < AWFUL_BAD) {
  142.                 if (pi <= EJECT_PENALTY) {
  143.                     c = pi;
  144.                 } else if (b < INF_BAD) {
  145.                     c = b + pi + insert_penalties;
  146.                 } else {
  147.                     c = DEPLORABLE;
  148.                 }
  149.             } else {
  150.                 c = b;
  151.             }
  152.             if (insert_penalties >= 10000) {
  153.                 c = AWFUL_BAD;
  154.             }
  155.             if (tracing_pages > 0) {
  156.                 show_page_stats(b, pi, c);
  157.             }
  158.             if (c <= least_page_cost) {
  159.                 best_page_break = p;
  160.                 best_size = page_goal;
  161.                 least_page_cost = c;
  162.                 r = link(page_ins_head);
  163.                 while (r != page_ins_head) {
  164.                     best_ins_ptr(r) = last_ins_ptr(r);
  165.                     r = link(r);
  166.                 }
  167.             }
  168.             if (c == AWFUL_BAD || pi <= EJECT_PENALTY) {
  169.                 fire_up(p);
  170.                 if (output_active) {
  171.                     return;
  172.                 }
  173.                 continue;
  174.             }
  175.         }
  176.         if (type(p) < GLUE_NODE || type(p) > KERN_NODE) {
  177.             goto contribute;
  178.         }
  179.         
  180.     update_heights:
  181.         if (type(p) == KERN_NODE) {
  182.             page_total += page_depth + kern_width(p);
  183.         } else {
  184.             q = glue_ptr(p);
  185.             page_so_far[2 + stretch_order(q)] += stretch(q);
  186.             page_shrink += shrink(q);
  187.             if (shrink_order(q) != NORMAL && shrink(q) != 0) {
  188.                 print_err(INF_SHRINK_PAGE);
  189.                 help_inf_shrink_page();
  190.                 error();
  191.                 r = new_spec(q);
  192.                 shrink_order(r) = NORMAL;
  193.                 delete_glue_ref(q);
  194.                 q = glue_ptr(p) = r;
  195.             }
  196.             page_total += page_depth + glue_width(q);
  197.         }
  198.         page_depth = 0;
  199.  
  200.     contribute:
  201.         if (page_depth > page_max_depth) {
  202.             page_total = page_total + page_depth - page_max_depth;
  203.             page_depth = page_max_depth;
  204.         }
  205.         page_tail = link(page_tail) = p;
  206.         link(contrib_head) = link(p);
  207.         link(p) = null;
  208.         continue;
  209.  
  210.     done:
  211.         link(contrib_head) = link(p);
  212.         link(p) = null;
  213.         flush_node_list(p);
  214.     } while (link(contrib_head) != null);
  215.     if (nest_ptr == nest) {
  216.         tail = contrib_head;
  217.     } else {
  218.         contrib_tail = contrib_head;
  219.     }
  220. }
  221.  
  222. void
  223. insert_page (p)
  224.     ptr    p;
  225. {
  226.     int    n;
  227.     ptr    q, r;
  228.     scal    h, w;
  229.     scal    delta;
  230.  
  231.     if (page_contents == EMPTY) {
  232.         freeze_page_specs(INSERTS_ONLY);
  233.     }
  234.     n = subtype(p);
  235.     r = page_ins_head;
  236.     while (n >= subtype(link(r))) {
  237.         r = link(r);
  238.     }
  239.     if (subtype(r) != n) {
  240.         q = new_node(PAGE_INS_NODE_SIZE);
  241.         link(q) = link(r);
  242.         r = link(r) = q;
  243.         subtype(r) = n;
  244.         type(r) = INSERTING;
  245.         ensure_vbox(n);
  246.         page_ins_height(r) = (box(n) == null) ? 0 :
  247.             box_height(box(n)) + box_depth(box(n));
  248.         best_ins_ptr(r) = null;
  249.         q = skip(n);
  250.         if (count(n) == 1000) {
  251.             h = page_ins_height(r);
  252.         } else {
  253.             h = x_over_n(page_ins_height(r), 1000) * count(n);
  254.         }
  255.         page_goal -= h + glue_width(q);
  256.         page_so_far[2 + stretch_order(q)] += stretch(q);
  257.         page_shrink += shrink(q);
  258.         if (shrink_order(q) != NORMAL && shrink(q) != 0) {
  259.             print_err("Infinite glue shrinkage inserted from ");
  260.             print_esc("skip");
  261.             print_int(n);
  262.             help_inf_shrink_ins();
  263.             error();
  264.         }
  265.     }
  266.     if (type(r) == SPLIT_UP) {
  267.         insert_penalties += float_cost(p);
  268.         return;
  269.     }
  270.     last_ins_ptr(r) = p;
  271.     delta = page_goal - page_total - page_depth + page_shrink;
  272.     if (count(n) == 1000) {
  273.         h = ins_height(p);
  274.     } else {
  275.         h = x_over_n(ins_height(p), 1000) * count(n);
  276.     }
  277.     if ((h <= 0 || h <= delta)
  278.     && ins_height(p) + page_ins_height(r) <= dimen(n)) {
  279.         page_goal -= h;
  280.         page_ins_height(r) += ins_height(p);
  281.     } else {
  282.         if (count(n) <= 0) {
  283.             w = MAX_DIMEN;
  284.         } else {
  285.             w = page_goal - page_total - page_depth;
  286.             if (count(n) != 1000)  {
  287.                 w = x_over_n(w, count(n)) * 1000;
  288.             }
  289.         }
  290.         if (w > dimen(n) - page_ins_height(r)) {
  291.             w = dimen(n) - page_ins_height(r);
  292.         }
  293.         q = vert_break(ins_ptr(p), w, ins_depth(p));
  294.         page_ins_height(r) += best_height_plus_depth;
  295.         if (tracing_pages > 0) {
  296.             show_split(n, w, q);
  297.         }
  298.         if (count(n) != 1000) {
  299.             best_height_plus_depth =
  300.                 x_over_n(best_height_plus_depth, 1000) *
  301.                     count(n);
  302.         }
  303.         page_goal -= best_height_plus_depth;
  304.         type(r) = SPLIT_UP;
  305.         broken_ptr(r) = q;
  306.         broken_ins(r) = p;
  307.         if (q == null) {
  308.             insert_penalties += EJECT_PENALTY;
  309.         } else if (type(q) == PENALTY_NODE) {
  310.             insert_penalties += penalty(q);
  311.         }
  312.     }
  313. }
  314.  
  315. ptr
  316. vert_break (p, h, d)
  317.     ptr    p;
  318.     scal    h;
  319.     scal    d;
  320. {
  321.     int    b;
  322.     ptr    q;
  323.     ptr    r;
  324.     int    t;
  325.     int    pi;
  326.     ptr    prev_p;
  327.     scal    prev_dp;
  328.     ptr    best_place;
  329.     int    least_cost;
  330.  
  331. #define    INF_SHRINK_BOX "Infinite glue shrinkage found in box being split"
  332.  
  333.     prev_p = p;
  334.     least_cost = AWFUL_BAD;
  335.     do_all_six(set_height_zero);
  336.     prev_dp = 0;
  337.     loop {
  338.         if (p == null) {
  339.             pi = EJECT_PENALTY;
  340.         } else {
  341.             switch (type(p))
  342.             {
  343.             case HLIST_NODE:
  344.             case VLIST_NODE:
  345.             case RULE_NODE:
  346.                 cur_height += prev_dp + box_height(p);
  347.                 prev_dp = box_depth(p);
  348.                 goto not_found;
  349.             
  350.             case WHATSIT_NODE:
  351.                 goto not_found;
  352.             
  353.             case GLUE_NODE:
  354.                 if (precedes_break(prev_p)) {
  355.                     pi = 0;
  356.                 } else {
  357.                     goto update_heights;
  358.                 }
  359.                 break;
  360.             
  361.             case KERN_NODE:
  362.                 if (link(p) == null) {
  363.                     t = PENALTY_NODE;
  364.                 } else {
  365.                     t = type(link(p));
  366.                 }
  367.                 if (t == GLUE_NODE) {
  368.                     pi = 0;
  369.                 } else {
  370.                     goto update_heights;
  371.                 }
  372.                 break;
  373.             
  374.             case PENALTY_NODE:
  375.                 pi = penalty(p);
  376.                 break;
  377.             
  378.             case MARK_NODE:
  379.             case INS_NODE:
  380.                 goto not_found;
  381.             
  382.             default:
  383.                 confusion("vertbreak");
  384.             }
  385.         }
  386.         if (pi < INF_PENALTY) {
  387.             b = vert_badness(h);
  388.             if (b < AWFUL_BAD) {
  389.                 if (pi <= EJECT_PENALTY) {
  390.                     b = pi;
  391.                 } else if (b < INF_BAD) {
  392.                     b += pi;
  393.                 } else {
  394.                     b = DEPLORABLE;
  395.                 }
  396.             }
  397.             if (b <= least_cost) {
  398.                 best_place = p;
  399.                 least_cost = b;
  400.                 best_height_plus_depth = cur_height + prev_dp;
  401.             }
  402.             if (b == AWFUL_BAD || pi <= EJECT_PENALTY) {
  403.                 return best_place;
  404.             }
  405.         }
  406.         if (type(p) < GLUE_NODE || type(p) > KERN_NODE) {
  407.             goto not_found;
  408.         }
  409.  
  410.     update_heights:
  411.         if (type(p) == KERN_NODE) {
  412.             cur_height += prev_dp + kern_width(p);
  413.         } else {
  414.             q = glue_ptr(p);
  415.             active_height[2 + stretch_order(q)] += stretch(q);
  416.             active_height[6] += shrink(q);
  417.             if (shrink_order(q) != NORMAL && shrink(q) != 0) {
  418.                 print_err(INF_SHRINK_BOX);
  419.                 help_inf_shrink_box();
  420.                 error();
  421.                 r = new_spec(q);
  422.                 delete_glue_ref(q);
  423.                 shrink_order(r) = NORMAL;
  424.                 glue_ptr(p) = r;
  425.             }
  426.             cur_height += prev_dp + glue_width(q);
  427.         }
  428.         prev_dp = 0;
  429.  
  430.     not_found:
  431.         if (prev_dp > d) {
  432.             cur_height = cur_height + prev_dp - d;
  433.             prev_dp = d;
  434.         }
  435.         prev_p = p;
  436.         p = link(prev_p);
  437.     }
  438. }
  439.  
  440. ptr
  441. vsplit (n, h)
  442.     int    n;
  443.     scal    h;
  444. {
  445.     ptr    p;
  446.     ptr    q;
  447.     ptr    v;
  448.  
  449.     v = box(n);
  450.     if (split_first_mark != null) {
  451.         delete_token_ref(split_first_mark);
  452.         split_first_mark = null;
  453.         delete_token_ref(split_bot_mark);
  454.         split_bot_mark = null;
  455.     }
  456.     if (v == null) {
  457.         return null;
  458.     }
  459.     if (type(v) != VLIST_NODE) {
  460.         print_err(null_str);
  461.         print_esc("vsplit");
  462.         print(" needs a ");
  463.         print_esc("vbox");
  464.         help_vsplit_vbox();
  465.         error();
  466.         return null;
  467.     }
  468.     q = vert_break(list_ptr(v), h, split_max_depth);
  469.     p = list_ptr(v);
  470.     if (p == q) {
  471.         list_ptr(v) = null;
  472.     } else {
  473.         loop {
  474.             if (type(p) == MARK_NODE) {
  475.                 if (split_first_mark == null) {
  476.                     split_first_mark = mark_ptr(p);
  477.                     split_bot_mark = split_first_mark;
  478.                     token_ref_count(split_first_mark) += 2;
  479.                 } else {
  480.                     delete_token_ref(split_bot_mark);
  481.                     split_bot_mark = mark_ptr(p);
  482.                     add_token_ref(split_bot_mark);
  483.                 }
  484.             }
  485.             if (link(p) == q) {
  486.                 link(p) = null;
  487.                 break;
  488.             }
  489.             p = link(p);
  490.         }
  491.     }
  492.     q = prune_page_top(q);
  493.     p = list_ptr(v);
  494.     free_node(v, BOX_NODE_SIZE);
  495.     if (q == null) {
  496.         box(n) = null;
  497.     } else {
  498.         box(n) = vpack(q, NATURAL);
  499.     }
  500.     return (vpackage(p, h, EXACTLY, split_max_depth));
  501. }
  502.  
  503. ptr
  504. prune_page_top (p)
  505.     ptr    p;
  506. {
  507.     mcell    m;
  508.     ptr    prev_p;
  509.     ptr    q, s, t;
  510.  
  511.     t = (ptr)&m;
  512.     prev_p = t;
  513.     link(t) = p;
  514.     while (p != null) {
  515.         switch (type(p))
  516.         {
  517.         case HLIST_NODE:
  518.         case VLIST_NODE:
  519.         case RULE_NODE:
  520.             q = new_skip_param(SPLIT_TOP_SKIP_CODE);
  521.             link(prev_p) = q;
  522.             link(q) = p;
  523.             s = glue_ptr(q);
  524.             if (glue_width(s) > box_height(p)) {
  525.                 glue_width(s) -= box_height(p);
  526.             } else {
  527.                 glue_width(s) = 0;
  528.             }
  529.             p = null;
  530.             break;
  531.  
  532.         case WHATSIT_NODE:
  533.         case MARK_NODE:
  534.         case INS_NODE:
  535.             prev_p = p;
  536.             p = link(p);
  537.             break;
  538.         
  539.         case GLUE_NODE:
  540.         case KERN_NODE:
  541.         case PENALTY_NODE:
  542.             q = p;
  543.             p = link(p);
  544.             link(q) = null;
  545.             link(prev_p) = p;
  546.             flush_node_list(q);
  547.             break;
  548.  
  549.         default:
  550.             confusion("pruning");
  551.             break;
  552.         }
  553.     }
  554.     return (link(t));
  555. }
  556.  
  557. int
  558. page_badness ()
  559. {
  560.     int    b;
  561.  
  562.     if (page_total < page_goal) {
  563.         if (page_so_far[3] != 0
  564.         || page_so_far[4] != 0
  565.         || page_so_far[5] != 0) {
  566.             b = 0;
  567.         } else {
  568.             b = badness(page_goal - page_total, page_so_far[2]);
  569.         }
  570.     } else if (page_total - page_goal > page_shrink) {
  571.         b = AWFUL_BAD;
  572.     } else {
  573.         b = badness(page_total - page_goal, page_shrink);
  574.     }
  575.     return b;
  576. }
  577.  
  578. int
  579. vert_badness (height)
  580.     int    height;
  581. {
  582.     int    b;
  583.  
  584.     if (cur_height < height) {
  585.         if (active_height[3] != 0
  586.         || active_height[4] != 0
  587.         || active_height[5] != 0) {
  588.             b = 0;
  589.         } else {
  590.             b = badness(height - cur_height, active_height[2]);
  591.         }
  592.     } else if (cur_height - height > active_height[6]) {
  593.         b = AWFUL_BAD;
  594.     } else  {
  595.         b = badness(cur_height - height, active_height[6]);
  596.     }
  597.     return b;
  598. }
  599.  
  600. void
  601. freeze_page_specs (s)
  602.     int    s;
  603. {
  604.     page_contents = s;
  605.     page_goal = vsize;
  606.     page_max_depth = max_depth;
  607.     page_depth = 0;
  608.     do_all_six(set_page_so_far_zero);
  609.     least_page_cost = AWFUL_BAD;
  610.     if (tracing_pages > 0) {
  611.         begin_diagnostic();
  612.         print_nl("%% goal height=");
  613.         print_scaled(page_goal);
  614.         print(", max depth=");
  615.         print_scaled(page_max_depth);
  616.         end_diagnostic(FALSE);
  617.     }
  618. }
  619.  
  620. void
  621. box_error (n)
  622.     int    n;
  623. {
  624.     error();
  625.     begin_diagnostic();
  626.     print_nl("The following box has been deleted:");
  627.     show_box(box(n));
  628.     end_diagnostic(TRUE);
  629.     flush_node_list(box(n));
  630.     box(n) = null;
  631. }
  632.  
  633. void
  634. ensure_vbox (n)
  635.     int    n;
  636. {
  637.     ptr    p;
  638.  
  639.     p = box(n);
  640.     if (p != null && type(p) == HLIST_NODE) {
  641.         print_err("Insertions can only be added to a vbox");
  642.         help_tut();
  643.         box_error(n);
  644.     }
  645. }
  646.  
  647. void
  648. print_plus (s, o)
  649.     int    s;
  650.     str    o;
  651. {
  652.     if (page_so_far[s] != 0) {
  653.         print(" plus ");
  654.         print_scaled(page_so_far[s]);
  655.         print(o);
  656.     }
  657. }
  658.  
  659. void
  660. print_totals ()
  661. {
  662.     print_scaled(page_total);
  663.     print_plus(2, null_str);
  664.     print_plus(3, "fil");
  665.     print_plus(4, "fill");
  666.     print_plus(5, "filll");
  667.     if (page_shrink != 0) {
  668.         print(" minus ");
  669.         print_scaled(page_shrink);
  670.     }
  671. }
  672.  
  673. void
  674. show_split(n, w, q)
  675.     int    n;
  676.     scal    w;
  677.     ptr    q;
  678. {
  679.     begin_diagnostic();
  680.     print_nl("% split");
  681.     print_int(n);
  682.     print(" to ");
  683.     print_scaled(w);
  684.     print_char(',');
  685.     print_scaled(best_height_plus_depth);
  686.     print(" p=");
  687.     if (q == null) {
  688.         print_int(EJECT_PENALTY);
  689.     } else if (type(q) == PENALTY_NODE) {
  690.         print_int(penalty(q));
  691.     } else {
  692.         print("0");
  693.     }
  694.     end_diagnostic(FALSE);
  695. }
  696.  
  697. void
  698. show_page_stats (b, pi, c)
  699.     int    b;
  700.     int    pi;
  701.     int    c;
  702. {
  703.     begin_diagnostic();
  704.     print_nl("%");
  705.     print(" t=");
  706.     print_totals();
  707.     print(" g=");
  708.     print_scaled(page_goal);
  709.     print(" b=");
  710.     if (b == AWFUL_BAD) {
  711.         print_char('*');
  712.     } else {
  713.         print_int(b);
  714.     }
  715.     print(" p=");
  716.     print_int(pi);
  717.     print(" c=");
  718.     if (c == AWFUL_BAD) {
  719.         print("*");
  720.     } else {
  721.         print_int(c);
  722.     }
  723.     if (c <= least_page_cost) {
  724.         print("#");
  725.     }
  726.     end_diagnostic(FALSE);
  727. }
  728.  
  729. #define set_output_penalty(P) \
  730.     reg_gdefine(int_reg[OUTPUT_PENALTY_CODE], INT_REG, P)
  731.  
  732.     
  733. void
  734. fire_up (c)
  735.     ptr    c;
  736. {
  737.     int    n;
  738.     bool    wait;
  739.     ptr    prev_p;
  740.     scal    save_vfuzz;
  741.     int    save_vbadness;
  742.     ptr    save_split_top_skip;
  743.     ptr    p, q, r;
  744.  
  745.     if (type(best_page_break) == PENALTY_NODE) {
  746.         set_output_penalty(penalty(best_page_break));
  747.         penalty(best_page_break) = INF_PENALTY;
  748.     } else {
  749.         set_output_penalty(INF_PENALTY);
  750.     }
  751.     if (bot_mark != null) {
  752.         if (top_mark != null) {
  753.             delete_token_ref(top_mark);
  754.         }
  755.         top_mark = bot_mark;
  756.         add_token_ref(top_mark);
  757.         delete_token_ref(first_mark);
  758.         first_mark = null;
  759.     }
  760.     if (c == best_page_break) {
  761.         best_page_break = null;
  762.     }
  763.     if (box(255) != null) {
  764.         print_err(null_str);
  765.         print_esc("box");
  766.         print("255 is not void");
  767.         help_box_255();
  768.         box_error(255);
  769.     }
  770.     insert_penalties = 0;
  771.     save_split_top_skip = split_top_skip;
  772.     if (holding_inserts <= 0) {
  773.         r = link(page_ins_head);
  774.         while (r != page_ins_head) {
  775.             if (best_ins_ptr(r) != null) {
  776.                 n = subtype(r);
  777.                 ensure_vbox(n);
  778.                 if (box(n) == null) {
  779.                     box(n) = new_null_box();
  780.                 }
  781.                 p = node_list(box(n));
  782.                 while (link(p) != null) {
  783.                     p = link(p);
  784.                 }
  785.                 last_ins_ptr(r) = p;
  786.             }
  787.             r = link(r);
  788.         }
  789.     }
  790.     q = hold_head;
  791.     link(q) = null;
  792.     prev_p = page_head;
  793.     p = link(prev_p);
  794.     while (p != best_page_break) {
  795.         if (type(p) == INS_NODE) {
  796.             if (holding_inserts <= 0) {
  797.                 wait = insert_box(p);
  798.                 link(prev_p) = link(p);
  799.                 link(p) = null;
  800.                 if (wait) {
  801.                     q = link(q) = p;
  802.                     incr(insert_penalties);
  803.                 } else {
  804.                     delete_glue_ref(split_top_ptr(p));
  805.                     free_node(p, INS_NODE_SIZE);
  806.                 }
  807.                 p = prev_p;
  808.             }
  809.         } else if (type(p) == MARK_NODE) {
  810.             if (first_mark == null) {
  811.                 first_mark = mark_ptr(p);
  812.                 add_token_ref(first_mark);
  813.             }
  814.             if (bot_mark != null) {
  815.                 delete_token_ref(bot_mark);
  816.             }
  817.             bot_mark = mark_ptr(p);
  818.             add_token_ref(bot_mark);
  819.         }
  820.         prev_p = p;
  821.         p = link(prev_p);
  822.     }
  823.     split_top_skip = save_split_top_skip;
  824.     if (p != null) {
  825.         if (link(contrib_head) == null) {
  826.             if (nest_ptr == nest) {
  827.                 tail = page_tail;
  828.             } else {
  829.                 contrib_tail = page_tail;
  830.             }
  831.         }
  832.         link(page_tail) = link(contrib_head);
  833.         link(contrib_head) = p;
  834.         link(prev_p) = null;
  835.     }
  836.     save_vbadness = vbadness;
  837.     save_vfuzz = vfuzz;
  838.     vbadness = INF_BAD;
  839.     vfuzz = MAX_DIMEN;
  840.     box(255) = vpackage(link(page_head),
  841.         best_size, EXACTLY, page_max_depth);
  842.     vbadness = save_vbadness;
  843.     vfuzz = save_vfuzz;
  844.     if (last_glue != null) {
  845.         delete_glue_ref(last_glue);
  846.     }
  847.     start_new_page();
  848.     if (q != hold_head) {
  849.         link(page_head) = link(hold_head);
  850.         page_tail = q;
  851.     }
  852.     r = link(page_ins_head);
  853.     while (r != page_ins_head) {
  854.         q = link(r);
  855.         free_node(r, PAGE_INS_NODE_SIZE);
  856.         r = q;
  857.     }
  858.     link(page_ins_head) = page_ins_head;
  859.     if (top_mark != null && first_mark == null) {
  860.         first_mark = top_mark;
  861.         add_token_ref(top_mark);
  862.     }
  863.     if (output_routine != null) {
  864.         if (dead_cycles >= max_dead_cycles) {
  865.             print_err("Output loop---");
  866.             print_int(dead_cycles);
  867.             print(" consecutive dead cycles");
  868.             help_dead_cycles();
  869.             error();
  870.         } else {
  871.             output_active = TRUE;
  872.             incr(dead_cycles);
  873.             push_nest();
  874.             mode = -VMODE;
  875.             prev_depth = IGNORE_DEPTH;
  876.             mode_line = -line;
  877.             begin_token_list(output_routine, OUTPUT_TEXT);
  878.             new_save_level(OUTPUT_GROUP);
  879.             normal_paragraph();
  880.             scan_left_brace();
  881.             return;
  882.         }
  883.     }
  884.     if (link(page_head) != null) {
  885.         if (link(contrib_head) == null) {
  886.             if (nest_ptr == nest) {
  887.                 tail = page_tail;
  888.             } else {
  889.                 contrib_tail = page_tail;
  890.             }
  891.         } else {
  892.             link(page_tail) = link(contrib_head);
  893.         }
  894.         link(contrib_head) = link(page_head);
  895.         link(page_head) = null;
  896.         page_tail = page_head;
  897.     }
  898.     ship_out(box(255));
  899.     box(255) = null;
  900. }
  901.  
  902. bool
  903. insert_box (p)
  904.     ptr    p;
  905. {
  906.     bool    wait;
  907.     ptr    q, r, t;
  908.     int    n;
  909.  
  910.     q = link(page_ins_head);
  911.     while (subtype(q) != subtype(p)) {
  912.         q = link(q);
  913.     }
  914.     if (best_ins_ptr(q) == null) {
  915.         return TRUE;
  916.     }
  917.     wait = FALSE;
  918.     r = last_ins_ptr(q);
  919.     link(r) = ins_ptr(p);
  920.     if (best_ins_ptr(q) == p) {
  921.         if (type(q) == SPLIT_UP
  922.         && broken_ins(q) == p
  923.         && broken_ptr(q) != null) {
  924.             while (link(r) != broken_ptr(q)) {
  925.                 r = link(r);
  926.             }
  927.             link(r) = null;
  928.             split_top_skip = split_top_ptr(p);
  929.             ins_ptr(p) = prune_page_top(broken_ptr(q));
  930.             if (ins_ptr(p) != null) {
  931.                 t = vpack(ins_ptr(p), NATURAL);
  932.                 ins_height(p) = box_height(t) + box_depth(t);
  933.                 free_node(t, BOX_NODE_SIZE);
  934.                 wait = TRUE;
  935.             }
  936.         }
  937.         best_ins_ptr(q) = null;
  938.         n = subtype(q);
  939.         t = list_ptr(box(n));
  940.         free_node(box(n), BOX_NODE_SIZE);
  941.         box(n) = vpack(t, NATURAL);
  942.     } else {
  943.         while (link(r) != null) {
  944.             r = link(r);
  945.         }
  946.         last_ins_ptr(q) = r;
  947.     }
  948.     return wait;
  949. }
  950.  
  951. void
  952. show_cur_page ()
  953. {
  954.     ptr    p, q;
  955.     int    t;
  956.  
  957.     if (page_head == page_tail) {
  958.         return;
  959.     }
  960.     print_nl("### current page:");
  961.     if (output_active) {
  962.         print(" (held over for next output)");
  963.     }
  964.     show_box(link(page_head));
  965.     if (page_contents > EMPTY) {
  966.         print_nl("total height ");
  967.         print_totals();
  968.         print_nl(" goal height ");
  969.         print_scaled(page_goal);
  970.         p = link(page_ins_head);
  971.         while (p != page_ins_head) {
  972.             print_ln();
  973.             print_esc("insert");
  974.             t = subtype(p);
  975.             print_int(t);
  976.             print(" adds ");
  977.             t = x_over_n(page_ins_height(p), 1000) * count(t);
  978.             print_scaled(t);
  979.             if (type(p) == SPLIT_UP) {
  980.                 q = page_head;
  981.                 t = 0;
  982.                 do {
  983.                     q = link(q);
  984.                     if (type(q) == INS_NODE
  985.                     && subtype(q) == subtype(p)) {
  986.                         incr(t);
  987.                     }
  988.                 } while (q != broken_ins(p));
  989.                 print(", #");
  990.                 print_int(t);
  991.                 print(" might split");
  992.             }
  993.             p = link(p);
  994.         }
  995.     }
  996. }
  997.  
  998. void
  999. _page_init ()
  1000. {
  1001.     start_new_page();
  1002.     prev_depth = IGNORE_DEPTH;
  1003.     output_active = FALSE;
  1004.     insert_penalties = 0;
  1005. }
  1006.  
  1007. void
  1008. _page_init_once ()
  1009. {
  1010.     contrib_head = new_avail();
  1011.     page_tail = page_head = new_glue(zero_glue);
  1012.     page_ins_head = new_node(PAGE_INS_NODE_SIZE);
  1013.     link(page_ins_head) = page_ins_head;
  1014.     type(page_ins_head) = SPLIT_UP;
  1015.     subtype(page_ins_head) = 255;
  1016. }
  1017.  
  1018. /*
  1019. **    Help text
  1020. */
  1021.  
  1022. help_tut ()
  1023. {
  1024.     help3("Tut tut: You're trying to \\insert into a",
  1025.     "\\box register that now contains an \\hbox.",
  1026.     "Proceed, and I'll discard its present contents.");
  1027. }
  1028.  
  1029. help_vsplit_vbox ()
  1030. {
  1031.     help2("The box you are trying to split is an \\hbox.",
  1032.     "I can't split such a box, so I'll leave it alone.");
  1033. }
  1034.  
  1035. help_inf_shrink_ins ()
  1036. {
  1037.     help3("The correction glue for page breaking with insertions",
  1038.     "must have finite shrinkability. But you may proceed,",
  1039.     "since the offensive shrinkability has been made finite.");
  1040. }
  1041.  
  1042. help_inf_shrink_box ()
  1043. {
  1044.     help4("The box you are \\vsplitting contains some infinitely",
  1045.     "shrinkable glue, e.g., `\\vss' or `\\vskip 0pt minus 1fil'.",
  1046.     "Such glue doesn't belong there; but you can safely proceed,",
  1047.     "since the offensive shrinkability has been made finite.");
  1048. }
  1049.  
  1050. help_inf_shrink_page ()
  1051. {
  1052.     help4("The page about to be output contains some infinitely",
  1053.     "shrinkable glue, e.g., `\\vss' or `\\vskip 0pt minus 1fil'.",
  1054.     "Such glue doesn't belong there; but you can safely proceed,",
  1055.     "since the offensive shrinkability has been made finite.");
  1056. }
  1057.  
  1058. help_box_255 ()
  1059. {
  1060.     help2("You shouldn't use \\box255 except in \\output routines.",
  1061.     "Proceed, and I'll discard its present contents.");
  1062. }
  1063.  
  1064. help_dead_cycles ()
  1065. {
  1066.     help3("I've concluded that your \\output is awry; it never does a",
  1067.     "\\shipout, so I'm shipping \\box255 out myself. Next time",
  1068.     "increase \\maxdeadcycles if you want me to be more patient!");
  1069. }
  1070.