home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Tex / Tex29 / StTeXsrc.zoo / src / page.c < prev    next >
C/C++ Source or Header  |  1988-03-13  |  25KB  |  882 lines

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