home *** CD-ROM | disk | FTP | other *** search
/ Mega Top 1 / os2_top1.zip / os2_top1 / APPS / TEKST / CMTEX330 / SOURCE / PAR.C < prev    next >
C/C++ Source or Header  |  1992-02-19  |  23KB  |  1,169 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    cur_p;
  20.  
  21. ptr    active;
  22. ptr    passive;
  23.  
  24. ptr    cur_r;
  25. ptr    prev_r;
  26. ptr    prev_prev_r;
  27.  
  28. scal    background[7];
  29. scal    break_width[7];
  30. scal    active_width[7];
  31. scal    cur_active_width[7];
  32.  
  33. int    threshold;
  34. bool    second_pass;
  35. bool    final_pass;
  36. scal    first_indent;
  37. scal    first_width;
  38. scal    second_indent;
  39. scal    second_width;
  40.  
  41. int    fewest_demerits;
  42. int    minimum_demerits;
  43. int    minimal_demerits[4];
  44. int    best_pl_line[4];
  45. ptr    best_place[4];
  46. ptr    best_bet;
  47. int    best_line;
  48. int    fit_class;
  49.  
  50. int    easy_line;
  51. int    last_special_line;
  52. int    line_diff;
  53. scal    line_width;
  54. scal    disc_width;
  55. int    pass_number;
  56. ptr    printed_node;
  57. int    actual_looseness;
  58. bool    no_shrink_error_yet;
  59.  
  60. ptr    just_box;
  61.  
  62. #define act_width    active_width[1]
  63.  
  64. #define width_lig_char(C) \
  65.     char_width(font(lig_char(C)), \
  66.         char_info(font(lig_char(C)), character(lig_char(C))))
  67.  
  68. #define width_char(C) \
  69.     char_width(font(C), char_info(font(C), character(C)))
  70.  
  71. #define check_shrinkage(G) \
  72.     {if (shrink_order(G) != NORMAL && shrink(G) != 0) \
  73.         G = finite_shrink(G);}
  74.  
  75. void
  76. line_break (final_widow_penalty)
  77.     int    final_widow_penalty;
  78. {
  79.     ptr    q, r, t;
  80.     ptr    prev_p;
  81.     bool    auto_breaking;
  82.  
  83.     pack_begin_line = mode_line;
  84.     t = new_avail();
  85.     link(t) = link(head);
  86.     if (is_char_node(tail)) {
  87.         tail_append(new_penalty(INF_PENALTY));
  88.     } else if (type(tail) != GLUE_NODE) {
  89.         tail_append(new_penalty(INF_PENALTY));
  90.     } else {
  91.         type(tail) = PENALTY_NODE;
  92.         delete_glue_ref(glue_ptr(tail));
  93.         flush_node_list(leader_ptr(tail));
  94.         penalty(tail) = INF_PENALTY;
  95.     }
  96.     link(tail) = new_param_glue(PAR_FILL_SKIP_CODE);
  97.     pop_nest();
  98.     no_shrink_error_yet = TRUE;
  99.     check_shrinkage(left_skip);
  100.     check_shrinkage(right_skip);
  101.     q = left_skip;
  102.     r = right_skip;
  103.     background[1] = glue_width(q) + glue_width(r);
  104.     background[2] = 0;
  105.     background[3] = 0;
  106.     background[4] = 0;
  107.     background[5] = 0;
  108.     background[2 + stretch_order(q)] = stretch(q);
  109.     background[2 + stretch_order(r)] += stretch(r);
  110.     background[6] = shrink(q) + shrink(r);
  111.     minimum_demerits = AWFUL_BAD;
  112.     minimal_demerits[VERY_LOOSE_FIT] = AWFUL_BAD;
  113.     minimal_demerits[LOOSE_FIT] = AWFUL_BAD;
  114.     minimal_demerits[DECENT_FIT] = AWFUL_BAD;
  115.     minimal_demerits[TIGHT_FIT] = AWFUL_BAD;
  116.     if (par_shape_ptr == null) {
  117.         if (hang_indent == 0) {
  118.             last_special_line = 0;
  119.             second_width = hsize;
  120.             second_indent = 0;
  121.         } else {
  122.             last_special_line = abs(hang_after);
  123.             if (hang_after < 0) {
  124.                 first_width = hsize - abs(hang_indent);
  125.                 first_indent = hang_indent >= 0 ?
  126.                     hang_indent : 0;
  127.                 second_width = hsize;
  128.                 second_indent = 0;
  129.             } else {
  130.                 first_width = hsize;
  131.                 first_indent = 0;
  132.                 second_width = hsize - abs(hang_indent);
  133.                 second_indent = (hang_indent >= 0) ?
  134.                     hang_indent : 0;
  135.             }
  136.         }
  137.     } else {
  138.         last_special_line = info(par_shape_ptr) - 1;
  139.         second_width = par_shape_width(last_special_line + 1);
  140.         second_indent = par_shape_indent(last_special_line + 1);
  141.     }
  142.     easy_line = (looseness == 0) ? last_special_line : MAX_HALFWORD;
  143.     threshold = pretolerance;
  144.     if (threshold >= 0) {
  145.         if (tracing_paragraphs > 0) {
  146.             begin_diagnostic();
  147.             print_nl("@firstpass");
  148.         }
  149.         second_pass = FALSE;
  150.         final_pass = FALSE;
  151.     } else {
  152.         threshold = tolerance;
  153.         second_pass = TRUE;
  154.         final_pass = emergency_stretch <= 0;
  155.         if (tracing_paragraphs > 0) {
  156.             begin_diagnostic();
  157.         }
  158.     }
  159.  
  160. #define store_background(W) \
  161.     (active_width[W] = background[W])
  162.  
  163. next_pass:
  164.     if (threshold >= INF_BAD) {
  165.         threshold = INF_BAD;
  166.     }
  167.     if (second_pass) {
  168.         init_hyph();
  169.     }
  170.     q = new_node(ACTIVE_NODE_SIZE);
  171.     type(q) = UNHYPHENATED;
  172.     fitness(q) = DECENT_FIT;
  173.     link(q) = last_active;
  174.     break_node(q) = null;
  175.     line_number(q) = prev_graf + 1;
  176.     total_demerits(q) = 0;
  177.     link(active) = q;
  178.     do_all_six(store_background);
  179.     passive = null;
  180.     printed_node = t;
  181.     pass_number = 0;
  182.     font_in_short_display = null_font;
  183.     prev_p = cur_p = link(t);
  184.     auto_breaking = TRUE;
  185.     while (cur_p != null && link(active) != last_active) {
  186.         if (is_char_node(cur_p)) {
  187.             prev_p = cur_p;
  188.             while (is_char_node(cur_p)) {
  189.                 act_width += width_char(cur_p);
  190.                 cur_p = link(cur_p);
  191.             }
  192.         }
  193.         switch (type(cur_p))
  194.         {
  195.         case HLIST_NODE:
  196.         case VLIST_NODE:
  197.         case RULE_NODE:
  198.             act_width += box_width(cur_p);
  199.             break;
  200.         
  201.         case GLUE_NODE:
  202.             if (auto_breaking) {
  203.                 if (is_char_node(prev_p)
  204.                 || precedes_break(prev_p)) {
  205.                     try_break(0, UNHYPHENATED);
  206.                 }
  207.             }
  208.             check_shrinkage(glue_ptr(cur_p));
  209.             q = glue_ptr(cur_p);
  210.             act_width += glue_width(q);
  211.             active_width[2 + stretch_order(q)] += stretch(q);
  212.             active_width[6] += shrink(q);
  213.             if (second_pass && auto_breaking) {
  214.                 try_hyph();
  215.             }
  216.             break;
  217.         
  218.         case KERN_NODE:
  219.             if (!is_char_node(link(cur_p))
  220.             && auto_breaking
  221.             && type(link(cur_p)) == GLUE_NODE) {
  222.                 try_break(0, UNHYPHENATED);
  223.             }
  224.             act_width += kern_width(cur_p);
  225.             break;
  226.         
  227.         case LIGATURE_NODE:
  228.             act_width += width_lig_char(cur_p);
  229.             break;
  230.         
  231.         case DISC_NODE:
  232.             disc_width = 0;
  233.             if (pre_break(cur_p) == null) {
  234.                 try_break(ex_hyphen_penalty, HYPHENATED);
  235.             } else {
  236.                 set_disc_width();
  237.                 act_width += disc_width;
  238.                 try_break(hyphen_penalty, HYPHENATED);
  239.                 act_width -= disc_width;
  240.             }
  241.             prev_p = cur_p;
  242.             set_act_width();
  243.             continue;
  244.         
  245.         case MATH_NODE:
  246.             auto_breaking = subtype(cur_p) == AFTER;
  247.             if (!is_char_node(link(cur_p))
  248.             && auto_breaking
  249.             && type(link(cur_p)) == GLUE_NODE) {
  250.                 try_break(0, UNHYPHENATED);
  251.             }
  252.             act_width += math_width(cur_p);
  253.             break;
  254.         
  255.         case PENALTY_NODE:
  256.             try_break(penalty(cur_p), UNHYPHENATED);
  257.             break;
  258.         
  259.         case MARK_NODE:
  260.         case INS_NODE:
  261.         case ADJUST_NODE:
  262.             break;
  263.  
  264.         case WHATSIT_NODE:
  265.             line_break_whatsit(cur_p);
  266.             break;
  267.  
  268.         default:
  269.             confusion("paragraph");
  270.             break;
  271.         }
  272.         prev_p = cur_p;
  273.         cur_p = link(cur_p);
  274.     }
  275.     if (cur_p == null) {
  276.         try_break(EJECT_PENALTY, HYPHENATED);
  277.         if (link(active) != last_active) {
  278.             if (get_best_bet()) {
  279.                 goto done;
  280.             }
  281.         }
  282.     }
  283.     for (q = link(active); q != last_active; q = cur_p) {
  284.         cur_p = link(q);
  285.         if (type(q) == DELTA_NODE) {
  286.             free_node(q, DELTA_NODE_SIZE);
  287.         } else {
  288.             free_node(q, ACTIVE_NODE_SIZE);
  289.         }
  290.     }
  291.     for (q = passive; q != null; q = cur_p) {
  292.         cur_p = link(q);
  293.         free_node(q, PASSIVE_NODE_SIZE);
  294.     }
  295.     if (!second_pass) {
  296.         if (tracing_paragraphs > 0) {
  297.             print_nl("@secondpass");
  298.         }
  299.         threshold = tolerance;
  300.         second_pass = TRUE;
  301.         final_pass = emergency_stretch <= 0;
  302.     } else {
  303.         if (tracing_paragraphs > 0) {
  304.             print_nl("@emergencypass");
  305.         }
  306.         background[2] += emergency_stretch;
  307.         final_pass = TRUE;
  308.     }    
  309.     goto next_pass;
  310.  
  311. done:
  312.     if (tracing_paragraphs > 0) {
  313.         end_diagnostic(TRUE);
  314.         normalize_selector();
  315.     }
  316.     post_line_break(t, final_widow_penalty);
  317.     for (q = link(active); q != last_active; q = cur_p) {
  318.         cur_p = link(q);
  319.         if (type(q) == DELTA_NODE) {
  320.             free_node(q, DELTA_NODE_SIZE);
  321.         } else {
  322.             free_node(q, ACTIVE_NODE_SIZE);
  323.         }
  324.     }
  325.     for (q = passive; q != null; q = cur_p) {
  326.         cur_p = link(q);
  327.         free_node(q, PASSIVE_NODE_SIZE);
  328.     }
  329.     pack_begin_line = 0;
  330. }
  331.  
  332. void
  333. try_break (pi, break_type)
  334.     int    pi;
  335.     int    break_type;
  336. {
  337.     int    b, d;
  338.     int    l, old_l;
  339.     bool    artificial_demerits;
  340.     bool    cur_r_stays_active;
  341.     bool    no_break_yet;
  342.  
  343. #define update_width(W) \
  344.     (cur_active_width[W] += deltas(cur_r)[W])
  345.  
  346. #define downdate_width(W) \
  347.     (cur_active_width[W] -= deltas(prev_r)[W])
  348.  
  349. #define copy_to_cur_active(W) \
  350.     (cur_active_width[W] = active_width[W])
  351.  
  352. #define update_active(W) \
  353.     (active_width[W] += deltas(cur_r)[W])
  354.  
  355. #define combine_two_deltas(W) \
  356.     deltas(prev_r)[W] += deltas(cur_r)[W]
  357.  
  358.     if (abs(pi) >= INF_PENALTY) {
  359.         if (pi > 0) {
  360.             update_printed_node();
  361.             return;
  362.         } else {
  363.             pi = EJECT_PENALTY;
  364.         }
  365.     }
  366.     no_break_yet = TRUE;
  367.     prev_r = active;
  368.     old_l = 0;
  369.     do_all_six(copy_to_cur_active);
  370.     loop {
  371.         cur_r = link(prev_r);
  372.         if (type(cur_r) == DELTA_NODE) {
  373.             do_all_six(update_width);
  374.             prev_prev_r = prev_r;
  375.             prev_r = cur_r;
  376.             continue;
  377.         }
  378.         l = line_number(cur_r);
  379.         if (l > old_l) {
  380.             if (minimum_demerits < AWFUL_BAD
  381.             && (old_l != easy_line || cur_r == last_active)) {
  382.                 if (no_break_yet) {
  383.                     no_break_yet = FALSE;
  384.                     set_break_width(break_type);
  385.                 }
  386.                 get_active_nodes(cur_r, break_type);
  387.             }
  388.             if (cur_r == last_active) {
  389.                 update_printed_node();
  390.                 return;
  391.             }
  392.             if (l > easy_line) {
  393.                 line_width = second_width;
  394.                 old_l = MAX_HALFWORD - 1;
  395.             } else {
  396.                 old_l = l;
  397.                 if (l > last_special_line) {
  398.                     line_width = second_width;
  399.                 } else if (par_shape_ptr == null) {
  400.                     line_width = first_width;
  401.                 } else {
  402.                     line_width = par_shape_width(l);
  403.                 }
  404.             }
  405.         }
  406.         artificial_demerits = FALSE;
  407.         b = get_badness();
  408.         if (b > INF_BAD || pi == EJECT_PENALTY) {
  409.             if (final_pass && minimum_demerits == AWFUL_BAD
  410.             && link(cur_r) == last_active && prev_r == active) {
  411.                 artificial_demerits = TRUE;
  412.             } else if (b > threshold) {
  413.                 goto deactivate;
  414.             }
  415.             cur_r_stays_active = FALSE;
  416.         } else {
  417.             prev_r = cur_r;
  418.             if (b > threshold) {
  419.                 continue;
  420.             }
  421.             cur_r_stays_active = TRUE;
  422.         }
  423.         if (artificial_demerits) {
  424.             d = 0;
  425.         } else {
  426.             d = line_penalty + b;
  427.             if (abs(d) >= 10000) {
  428.                 d = 100000000;
  429.             } else {
  430.                 d = d * d;
  431.             }
  432.             if (pi != 0) {
  433.                 if (pi > 0) {
  434.                     d += pi * pi;
  435.                 } else if (pi > EJECT_PENALTY) {
  436.                     d -= pi * pi;
  437.                 }
  438.             }
  439.             if (break_type == HYPHENATED
  440.             && type(cur_r) == HYPHENATED) {
  441.                 if (cur_p != null) {
  442.                     d += double_hyphen_demerits;
  443.                 } else {
  444.                     d += final_hyphen_demerits;
  445.                 }
  446.             }
  447.             if (abs(fit_class - (int)fitness(cur_r)) > 1) {
  448.                 d += adj_demerits;
  449.             }
  450.         }
  451.         if (tracing_paragraphs > 0) {
  452.             show_break_status(cur_r, artificial_demerits, b, pi, d);
  453.         }
  454.         d += total_demerits(cur_r);
  455.         if (d <= minimal_demerits[fit_class]) {
  456.             minimal_demerits[fit_class] = d;
  457.             best_place[fit_class] = break_node(cur_r);
  458.             best_pl_line[fit_class] = l;
  459.             if (d < minimum_demerits) {
  460.                 minimum_demerits = d;
  461.             }
  462.         }
  463.         if (cur_r_stays_active) {
  464.             continue;
  465.         }
  466.  
  467.     deactivate:
  468.         link(prev_r) = link(cur_r);
  469.         free_node(cur_r, ACTIVE_NODE_SIZE);
  470.         if (prev_r == active) {
  471.             cur_r = link(active);
  472.             if (type(cur_r) == DELTA_NODE) {
  473.                 do_all_six(update_active);
  474.                 do_all_six(copy_to_cur_active);
  475.                 link(active) = link(cur_r);
  476.                 free_node(cur_r, DELTA_NODE_SIZE);
  477.             }
  478.         } else if (type(prev_r) == DELTA_NODE) {
  479.             cur_r = link(prev_r);
  480.             if (cur_r == last_active) {
  481.                 do_all_six(downdate_width);
  482.                 link(prev_prev_r) = last_active;
  483.                 free_node(prev_r, DELTA_NODE_SIZE);
  484.                 prev_r = prev_prev_r;
  485.             } else if (type(cur_r) == DELTA_NODE) {
  486.                 do_all_six(update_width);
  487.                 do_all_six(combine_two_deltas);
  488.                 link(prev_r) = link(cur_r);
  489.                 free_node(cur_r, DELTA_NODE_SIZE);
  490.             }
  491.         }
  492.     }
  493. }
  494.  
  495. void
  496. post_line_break (p, final_widow_penalty)
  497.     ptr    p;
  498.     int    final_widow_penalty;
  499. {
  500.     ptr    q;
  501.     ptr    r;
  502.     ptr    s;
  503.     int    t;
  504.     int    pen;
  505.     int    cur_line;
  506.     scal    cur_width;
  507.     scal    cur_indent;
  508.     bool    disc_break;
  509.     bool    post_disc_break;
  510.  
  511.     q = break_node(best_bet);
  512.     cur_p = null;
  513.     while (q != null) {
  514.         r = q;
  515.         q = prev_break(q);
  516.         next_break(r) = cur_p;
  517.         cur_p = r;
  518.     }
  519.     cur_line = prev_graf + 1;
  520.     do {
  521.         q = cur_break(cur_p);
  522.         disc_break = FALSE;
  523.         post_disc_break = FALSE;
  524.         if (q != null) {
  525.             if (type(q) == GLUE_NODE) {
  526.                 delete_glue_ref(glue_ptr(q));
  527.                 glue_ptr(q) = right_skip;
  528.                 subtype(q) = RIGHT_SKIP_CODE + 1;
  529.                 add_glue_ref(right_skip);
  530.                 goto done;
  531.             } else if (type(q) == DISC_NODE) {
  532.                 t = replace_count(q);
  533.                 if (t == 0) {
  534.                     r = link(q);
  535.                 } else {
  536.                     r = q;
  537.                     while (t > 1) {
  538.                         r = link(r);
  539.                         decr(t);
  540.                     }
  541.                     s = link(r);
  542.                     r = link(s);
  543.                     link(s) = null;
  544.                     flush_node_list(link(q));
  545.                     replace_count(q) = 0;
  546.                 }
  547.                 if (post_break(q) != null) {
  548.                     s = post_break(q);
  549.                     while (link(s) != null) {
  550.                         s = link(s);
  551.                     }
  552.                     link(s) = r;
  553.                     r = post_break(q);
  554.                     post_break(q) = null;
  555.                     post_disc_break = TRUE;
  556.                 }
  557.                 if (pre_break(q) != null) {
  558.                     s = pre_break(q);
  559.                     link(q) = s;
  560.                     while (link(s) != null) {
  561.                         s = link(s);
  562.                     }
  563.                     pre_break(q) = null;
  564.                     q = s;
  565.                 }
  566.                 link(q) = r;
  567.                 disc_break = TRUE;
  568.             } else if (type(q) == MATH_NODE) {
  569.                 math_width(q) = 0;
  570.             } else if (type(q) == KERN_NODE) {
  571.                 kern_width(q) = 0;
  572.             }
  573.         } else {
  574.             q = p;
  575.             while (link(q) != null) {
  576.                 q = link(q);
  577.             }
  578.         }
  579.         r = new_param_glue(RIGHT_SKIP_CODE);
  580.         link(r) = link(q);
  581.         q = link(q) = r;
  582.  
  583.     done:
  584.         r = link(q);
  585.         link(q) = null;
  586.         q = link(p);
  587.         link(p) = r;
  588.         if (left_skip != zero_glue) {
  589.             r = new_param_glue(LEFT_SKIP_CODE);
  590.             link(r) = q;
  591.             q = r;
  592.         }
  593.         if (cur_line > last_special_line) {
  594.             cur_width = second_width;
  595.             cur_indent = second_indent;
  596.         } else if (par_shape_ptr == null) {
  597.             cur_width = first_width;
  598.             cur_indent = first_indent;
  599.         } else {
  600.             cur_width = par_shape_width(cur_line);
  601.             cur_indent = par_shape_indent(cur_line);
  602.         }
  603.         adjust_tail = adjust_head;
  604.         just_box = hpack(q, cur_width, EXACTLY);
  605.         shift_amount(just_box) = cur_indent;
  606.         append_to_vlist(just_box);
  607.         if (adjust_head != adjust_tail) {
  608.             link(tail) = link(adjust_head);
  609.             tail = adjust_tail;
  610.         }
  611.         adjust_tail = null;
  612.         if (cur_line + 1 != best_line) {
  613.             pen = inter_line_penalty;
  614.             if (cur_line == prev_graf + 1) {
  615.                 pen += club_penalty;
  616.             }
  617.             if (cur_line + 2 == best_line) {
  618.                 pen += final_widow_penalty;
  619.             }
  620.             if (disc_break) {
  621.                 pen += broken_penalty;
  622.             }
  623.             if (pen != 0) {
  624.                 r = new_penalty(pen);
  625.                 link(tail) = r;
  626.                 tail = r;
  627.             }
  628.         }
  629.         incr(cur_line);
  630.         cur_p = next_break(cur_p);
  631.         if (cur_p != null && !post_disc_break) {
  632.             r = p;
  633.             loop {
  634.                 q = link(r);
  635.                 if (q == cur_break(cur_p)) {
  636.                     break;
  637.                 }
  638.                 if (is_char_node(q)) {
  639.                     break;
  640.                 }
  641.                 if (non_discardable(q)) {
  642.                     break;
  643.                 }
  644.                 if (subtype(q) == ACC_KERN
  645.                 && type(q) == KERN_NODE) {
  646.                     break;
  647.                 }
  648.                 r = q;
  649.             }
  650.             if (r != p) {
  651.                 link(r) = null;
  652.                 flush_node_list(link(p));
  653.                 link(p) = q;
  654.             }
  655.         }
  656.     } while (cur_p != null);
  657.     if (cur_line != best_line || link(p) != null) {
  658.         confusion("line breaking");
  659.     }
  660.     prev_graf = best_line - 1;
  661. }
  662.  
  663. void
  664. set_disc_width ()
  665. {
  666.     ptr    p;
  667.  
  668.     for (p = pre_break(cur_p); p != null; p = link(p)) {
  669.         if (is_char_node(p)) {
  670.             disc_width += width_char(p);
  671.         } else {
  672.             switch (type(p))
  673.             {
  674.             case LIGATURE_NODE:
  675.                 disc_width += width_lig_char(p);
  676.                 break;
  677.             
  678.             case HLIST_NODE:
  679.             case VLIST_NODE:
  680.                 disc_width += box_width(p);
  681.                 break;
  682.  
  683.             case RULE_NODE:
  684.                 disc_width += rule_width(p);
  685.                 break;
  686.  
  687.             case KERN_NODE:
  688.                 disc_width += kern_width(p);
  689.                 break;
  690.             
  691.             default:
  692.                 confusion("disc3");
  693.                 break;
  694.             }
  695.         }
  696.     }
  697. }
  698.  
  699. void
  700. set_act_width ()
  701. {
  702.     ptr    p;
  703.     int    n;
  704.  
  705.     p = link(cur_p);
  706.     for (n = replace_count(cur_p); n > 0; decr(n)) {
  707.         if (is_char_node(p)) {
  708.             act_width += width_char(p);
  709.         } else {
  710.             switch (type(p))
  711.             {
  712.             case LIGATURE_NODE:
  713.                 act_width += width_lig_char(p);
  714.                 break;
  715.             
  716.             case HLIST_NODE:
  717.             case VLIST_NODE:
  718.                 act_width += box_width(p);
  719.                 break;
  720.  
  721.             case RULE_NODE:
  722.                 act_width += rule_width(p);
  723.                 break;
  724.  
  725.             case KERN_NODE:
  726.                 act_width += kern_width(p);
  727.                 break;
  728.             
  729.             default:
  730.                 confusion("disc3");
  731.                 break;
  732.             }
  733.         }
  734.         p = link(p);
  735.     }
  736.     cur_p = p;
  737. }
  738.  
  739. void
  740. set_break_width (break_type)
  741.     int     break_type;
  742. {
  743.     int     t;
  744.     ptr     p, q;
  745.  
  746. #define set_break_width_to_background(W) \
  747.     (break_width[W] = background[W])
  748.  
  749.     do_all_six(set_break_width_to_background);
  750.     p = cur_p;
  751.     if (break_type > UNHYPHENATED && cur_p != null) {
  752.         t = replace_count(cur_p);
  753.         q = cur_p;
  754.         while (t > 0) {
  755.             decr(t);
  756.             q = link(q);
  757.             if (is_char_node(q)) {
  758.                 break_width[1] -= width_char(q);
  759.             } else {
  760.                 switch (type(q))
  761.                 {
  762.                 case LIGATURE_NODE:
  763.                     break_width[1] -= width_lig_char(q);
  764.                     break;
  765.  
  766.                 case HLIST_NODE:
  767.                 case VLIST_NODE:
  768.                     break_width[1] -= box_width(q);
  769.                     break;
  770.  
  771.                 case RULE_NODE:
  772.                     break_width[1] -= rule_width(q);
  773.                     break;
  774.  
  775.                 case KERN_NODE:
  776.                     break_width[1] -= kern_width(q);
  777.                     break;
  778.  
  779.                 default:
  780.                     confusion("disc1");
  781.                     break;
  782.                 }
  783.             }
  784.         }
  785.         for (p = post_break(cur_p); p != null; p = link(p)) {
  786.             if (is_char_node(p)) {
  787.                 break_width[1] += width_char(p);
  788.             } else {
  789.                 switch (type(p))
  790.                 {
  791.                 case LIGATURE_NODE:
  792.                     break_width[1] += width_lig_char(p);
  793.                     break;
  794.  
  795.                 case HLIST_NODE:
  796.                 case VLIST_NODE:
  797.                     break_width[1] += box_width(p);
  798.                     break;
  799.  
  800.                 case RULE_NODE:
  801.                     break_width[1] += rule_width(p);
  802.                     break;
  803.  
  804.                 case KERN_NODE:
  805.                     if (t == 0 && subtype(p) != ACC_KERN) {
  806.                         t = -1;
  807.                     } else {
  808.                         break_width[1] += kern_width(p);
  809.                     }
  810.                     break;
  811.  
  812.                 default:
  813.                     confusion("disc2");
  814.                     break;
  815.                 }
  816.             }
  817.             incr(t);
  818.         }
  819.         break_width[1] += disc_width;
  820.         if (t == 0) {
  821.             p = link(q);
  822.         }
  823.     }
  824.     while (p != null) {
  825.         if (is_char_node(p)) {
  826.             return;
  827.         }
  828.         switch (type(p))
  829.         {
  830.         case GLUE_NODE:
  831.             q = glue_ptr(p);
  832.             break_width[1] -= glue_width(q);
  833.             break_width[2 + stretch_order(q)] -= stretch(q);
  834.             break_width[6] -= shrink(q);
  835.             break;
  836.         
  837.         case PENALTY_NODE:
  838.             break;
  839.         
  840.         case MATH_NODE:
  841.             break_width[1] -= math_width(p);
  842.             break;
  843.  
  844.         case KERN_NODE:
  845.             if (subtype(p) == ACC_KERN)
  846.                 return;
  847.             break_width[1] -= kern_width(p);
  848.             break;
  849.  
  850.         default:
  851.             return;
  852.         }
  853.         p = link(p);
  854.     }
  855. }
  856.  
  857. int
  858. get_best_bet ()
  859. {
  860.     ptr    p;
  861.  
  862.     fewest_demerits = AWFUL_BAD;
  863.     for (p = link(active); p != last_active; p = link(p)) {
  864.         if (type(p) != DELTA_NODE) {
  865.             if (total_demerits(p) < fewest_demerits) {
  866.                 fewest_demerits = total_demerits(p);
  867.                 best_bet = p;
  868.             }
  869.         }
  870.     }
  871.     best_line = line_number(best_bet);
  872.     if (looseness == 0) {
  873.         return TRUE;
  874.     }
  875.     actual_looseness = 0;
  876.     for (p = link(active); p != last_active; p = link(p)) {
  877.         if (type(p) != DELTA_NODE) {
  878.             line_diff = line_number(p) - best_line;
  879.             if (line_diff < actual_looseness
  880.             && looseness <= line_diff
  881.             || line_diff > actual_looseness
  882.             && looseness >= line_diff) {
  883.                 best_bet = p;
  884.                 actual_looseness = line_diff;
  885.                 fewest_demerits = total_demerits(p);
  886.             } else if (line_diff == actual_looseness
  887.                 && total_demerits(p) < fewest_demerits) {
  888.                 best_bet = p;
  889.                 fewest_demerits = total_demerits(p);
  890.             }
  891.         }
  892.     }
  893.     best_line = line_number(best_bet);
  894.     if (actual_looseness == looseness || final_pass) {
  895.         return TRUE;
  896.     }
  897.     return FALSE;
  898. }
  899.  
  900. int
  901. get_badness ()
  902. {
  903.     scal    s;
  904.     int    b;
  905.  
  906.     s = line_width - cur_active_width[1];
  907.     if (s > 0) {
  908.         if (cur_active_width[3] != 0
  909.         || cur_active_width[4] != 0
  910.         || cur_active_width[5] != 0) {
  911.             fit_class = DECENT_FIT;
  912.             return 0;
  913.         }
  914.         if (s > 7230584 && cur_active_width[2] < 1663497) {
  915.             fit_class = VERY_LOOSE_FIT;
  916.             return INF_BAD;
  917.         }
  918.         b = badness(s, cur_active_width[2]);
  919.         if (b > 12) {
  920.             if (b > 99) {
  921.                 fit_class = VERY_LOOSE_FIT;
  922.             } else {
  923.                 fit_class = LOOSE_FIT;
  924.             }
  925.         } else {
  926.             fit_class = DECENT_FIT;
  927.         }
  928.     } else {
  929.         if (-s > cur_active_width[6]) {
  930.             b = INF_BAD + 1;
  931.         } else {
  932.             b = badness(-s, cur_active_width[6]);
  933.         }
  934.         if (b > 12) {
  935.             fit_class = TIGHT_FIT;
  936.         } else {
  937.             fit_class = DECENT_FIT;
  938.         }
  939.     }
  940.     return b;
  941. }
  942.  
  943. void
  944. get_active_nodes (r, break_type)
  945.     ptr    r;
  946.     int    break_type;
  947. {
  948.     ptr    q;
  949.  
  950. #define new_delta_to_break_width(W) \
  951.     deltas(q)[W] = break_width[W] - cur_active_width[W]
  952.  
  953. #define new_delta_from_break_width(W) \
  954.     deltas(q)[W] = cur_active_width[W] - break_width[W]
  955.  
  956. #define convert_to_break_width(W) \
  957.     deltas(prev_r)[W] += break_width[W] - cur_active_width[W]
  958.  
  959. #define store_break_width(W) \
  960.     (active_width[W] = break_width[W])
  961.  
  962.     if (type(prev_r) == DELTA_NODE) {
  963.         do_all_six(convert_to_break_width);
  964.     } else if (prev_r == active) {
  965.         do_all_six(store_break_width);
  966.     } else {
  967.         q = new_node(DELTA_NODE_SIZE);
  968.         link(q) = r;
  969.         type(q) = DELTA_NODE;
  970.         subtype(q) = 0;
  971.         do_all_six(new_delta_to_break_width);
  972.         prev_prev_r = prev_r;
  973.         prev_r = link(prev_r) = q;
  974.     }
  975.     if (abs(adj_demerits) >= AWFUL_BAD - minimum_demerits) {
  976.         minimum_demerits = AWFUL_BAD - 1;
  977.     } else {
  978.         minimum_demerits += abs(adj_demerits);
  979.     }
  980.     for (fit_class = VERY_LOOSE_FIT;
  981.         fit_class <= TIGHT_FIT;
  982.             incr(fit_class)) {
  983.         if (minimal_demerits[fit_class] <= minimum_demerits) {
  984.             q = get_break_node(fit_class, break_type);
  985.             link(q) = r;
  986.             prev_r = link(prev_r) = q;
  987.         }
  988.         minimal_demerits[fit_class] = AWFUL_BAD;
  989.     }
  990.     minimum_demerits = AWFUL_BAD;
  991.     if (r != last_active) {
  992.         q = new_node(DELTA_NODE_SIZE);
  993.         link(q) = r;
  994.         type(q) = DELTA_NODE;
  995.         subtype(q) = 0;
  996.         do_all_six(new_delta_from_break_width);
  997.         prev_prev_r = prev_r;
  998.         prev_r = link(prev_r) = q;
  999.     }
  1000. }
  1001.  
  1002. ptr
  1003. get_break_node (fit_class, break_type)
  1004.     int    fit_class, break_type;
  1005. {
  1006.     ptr    p;
  1007.  
  1008.     p = new_node(PASSIVE_NODE_SIZE);
  1009.     link(p) = passive;
  1010.     passive = p;
  1011.     cur_break(p) = cur_p;
  1012.     incr(pass_number);
  1013.     serial(p) = pass_number;
  1014.     prev_break(p) = best_place[fit_class];
  1015.     p = new_node(ACTIVE_NODE_SIZE);
  1016.     break_node(p) = passive;
  1017.     line_number(p) = best_pl_line[fit_class] + 1;
  1018.     fitness(p) = fit_class;
  1019.     type(p) = break_type;
  1020.     total_demerits(p) = minimal_demerits[fit_class];
  1021.     if (tracing_paragraphs > 0) {
  1022.         show_break_node(p, fit_class, break_type);
  1023.     }
  1024.     return p;
  1025. }
  1026.  
  1027. void
  1028. show_break_node (p, fit_class, break_type)
  1029.     ptr    p;
  1030.     int    fit_class;
  1031.     int    break_type;
  1032. {
  1033.     print_nl("@@");
  1034.     print_int(serial(passive));
  1035.     print(": line ");
  1036.     print_int(line_number(p) - 1);
  1037.     print(".");
  1038.     print_int(fit_class);
  1039.     if (break_type == HYPHENATED) {
  1040.         print("-");
  1041.     }
  1042.     print(" t=");
  1043.     print_int(total_demerits(p));
  1044.     print(" -> @@");
  1045.     if (prev_break(passive) == null) {
  1046.         print("0");
  1047.     } else {
  1048.         print_int(serial(prev_break(passive)));
  1049.     }
  1050. }
  1051.  
  1052. void
  1053. show_break_status (r, a, b, p, d)
  1054.     ptr    r;
  1055.     bool    a;
  1056.     int    b;
  1057.     int    p;
  1058.     int    d;
  1059. {
  1060.     ptr    save_link;
  1061.  
  1062.     if (printed_node != cur_p) {
  1063.         print_nl(null_str);
  1064.         if (cur_p == null) {
  1065.             short_display(link(printed_node));
  1066.         } else {
  1067.             save_link = link(cur_p);
  1068.             link(cur_p) = null;
  1069.             print_nl(null_str);
  1070.             short_display(link(printed_node));
  1071.             link(cur_p) = save_link;
  1072.         }
  1073.         printed_node = cur_p;
  1074.     }
  1075.     print_nl("@");
  1076.     if (cur_p == null) {
  1077.         print_esc("par");
  1078.     } else if (type(cur_p) != GLUE_NODE) {
  1079.         if (type(cur_p) == PENALTY_NODE) {
  1080.             print_esc("penalty");
  1081.         } else if (type(cur_p) == DISC_NODE) {
  1082.             print_esc("discretionary");
  1083.         } else if (type(cur_p) == KERN_NODE) {
  1084.             print_esc("kern");
  1085.         } else {
  1086.             print_esc("math");
  1087.         }
  1088.     }
  1089.     print(" via @@");
  1090.     if (break_node(r) == null) {
  1091.         print("0");
  1092.     } else {
  1093.         print_int(serial(break_node(r)));
  1094.     }
  1095.     print(" b=");
  1096.     if (b > INF_BAD) {
  1097.         print("*");
  1098.     } else {
  1099.         print_int(b);
  1100.     }
  1101.     print(" p=");
  1102.     print_int(p);
  1103.     print(" d=");
  1104.     if (a) {
  1105.         print("*");
  1106.     } else {
  1107.         print_int(d);
  1108.     }
  1109. }
  1110.  
  1111. void
  1112. update_printed_node ()
  1113. {
  1114.     int    t;
  1115.  
  1116.     if (cur_p == printed_node
  1117.     && cur_p != null
  1118.     && type(cur_p) == DISC_NODE) {
  1119.         for (t = replace_count(cur_p); t > 0; decr(t)) {
  1120.             printed_node = link(printed_node);
  1121.         }
  1122.     }
  1123. }
  1124.  
  1125. ptr
  1126. finite_shrink (p)
  1127.     ptr    p;
  1128. {
  1129.     ptr    q;
  1130.  
  1131.     if (no_shrink_error_yet) {
  1132.         no_shrink_error_yet = FALSE;
  1133.         print_err("Infinite glue shrinkage found in a paragraph");
  1134.         help_shrink();
  1135.         error();
  1136.     }
  1137.     q = new_spec(p);
  1138.     shrink_order(q) = NORMAL;
  1139.     delete_glue_ref(p);
  1140.     return q;
  1141. }
  1142.  
  1143. void
  1144. _par_init ()
  1145. {
  1146. }
  1147.  
  1148. void
  1149. _par_init_once ()
  1150. {
  1151.     active = new_node(ACTIVE_NODE_SIZE);
  1152.     type(active) = HYPHENATED;
  1153.     subtype(active) = 0;
  1154.     line_number(active) = MAX_HALFWORD;
  1155. }
  1156.  
  1157. /*
  1158. **    Help text
  1159. */
  1160.  
  1161. help_shrink()
  1162. {
  1163.     help5("The paragraph just ended includes some glue that has",
  1164.     "infinite shrinkability, e.g., `\\hskip 0pt minus 1fil'.",
  1165.     "Such glue doesn't belong there---it allows a paragraph",
  1166.     "of any length to fit on one line. But it's safe to proceed,",
  1167.     "since the offensive shrinkability has been made finite.");
  1168. }
  1169.